OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [drm/] [gamma_dma.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
2
 * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
3
 *
4
 * Copyright 1999 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
 * PRECISION INSIGHT 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 OTHER
25
 * DEALINGS IN THE SOFTWARE.
26
 *
27
 * Authors:
28
 *    Rickard E. (Rik) Faith <faith@valinux.com>
29
 *
30
 */
31
 
32
#include "gamma.h"
33
#include "drmP.h"
34
#include "drm.h"
35
#include "gamma_drm.h"
36
#include "gamma_drv.h"
37
 
38
#include <linux/interrupt.h>    /* For task queue support */
39
#include <linux/delay.h>
40
 
41
static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
42
                                      unsigned long length)
43
{
44
        drm_gamma_private_t *dev_priv =
45
                                (drm_gamma_private_t *)dev->dev_private;
46
        mb();
47
        while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax();
48
        GAMMA_WRITE(GAMMA_DMAADDRESS, address);
49
        while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4) cpu_relax();
50
        GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
51
}
52
 
53
void gamma_dma_quiescent_single(drm_device_t *dev)
54
{
55
        drm_gamma_private_t *dev_priv =
56
                                (drm_gamma_private_t *)dev->dev_private;
57
        while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax();
58
 
59
        while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax();
60
 
61
        GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
62
        GAMMA_WRITE(GAMMA_SYNC, 0);
63
 
64
        do {
65
                while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
66
                        ;
67
        } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
68
}
69
 
70
void gamma_dma_quiescent_dual(drm_device_t *dev)
71
{
72
        drm_gamma_private_t *dev_priv =
73
                                (drm_gamma_private_t *)dev->dev_private;
74
        while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax();
75
 
76
        while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax();
77
 
78
        GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
79
        GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
80
        GAMMA_WRITE(GAMMA_SYNC, 0);
81
 
82
        /* Read from first MX */
83
        do {
84
                while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)) cpu_relax();
85
        } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
86
 
87
        /* Read from second MX */
88
        do {
89
                while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000)) cpu_relax();
90
        } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
91
}
92
 
93
void gamma_dma_ready(drm_device_t *dev)
94
{
95
        drm_gamma_private_t *dev_priv =
96
                                (drm_gamma_private_t *)dev->dev_private;
97
        while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax();
98
}
99
 
100
static inline int gamma_dma_is_ready(drm_device_t *dev)
101
{
102
        drm_gamma_private_t *dev_priv =
103
                                (drm_gamma_private_t *)dev->dev_private;
104
        return(!GAMMA_READ(GAMMA_DMACOUNT));
105
}
106
 
107
void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
108
{
109
        drm_device_t     *dev = (drm_device_t *)device;
110
        drm_device_dma_t *dma = dev->dma;
111
        drm_gamma_private_t *dev_priv =
112
                                (drm_gamma_private_t *)dev->dev_private;
113
 
114
        atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */
115
 
116
        while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax();
117
        GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
118
        GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
119
        GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
120
        if (gamma_dma_is_ready(dev)) {
121
                                /* Free previous buffer */
122
                if (test_and_set_bit(0, &dev->dma_flag)) return;
123
                if (dma->this_buffer) {
124
                        gamma_free_buffer(dev, dma->this_buffer);
125
                        dma->this_buffer = NULL;
126
                }
127
                clear_bit(0, &dev->dma_flag);
128
 
129
                                /* Dispatch new buffer */
130
                queue_task(&dev->tq, &tq_immediate);
131
                mark_bh(IMMEDIATE_BH);
132
        }
133
}
134
 
135
/* Only called by gamma_dma_schedule. */
136
static int gamma_do_dma(drm_device_t *dev, int locked)
137
{
138
        unsigned long    address;
139
        unsigned long    length;
140
        drm_buf_t        *buf;
141
        int              retcode = 0;
142
        drm_device_dma_t *dma = dev->dma;
143
#if DRM_DMA_HISTOGRAM
144
        cycles_t         dma_start, dma_stop;
145
#endif
146
 
147
        if (test_and_set_bit(0, &dev->dma_flag)) return -EBUSY;
148
 
149
#if DRM_DMA_HISTOGRAM
150
        dma_start = get_cycles();
151
#endif
152
 
153
        if (!dma->next_buffer) {
154
                DRM_ERROR("No next_buffer\n");
155
                clear_bit(0, &dev->dma_flag);
156
                return -EINVAL;
157
        }
158
 
159
        buf     = dma->next_buffer;
160
        /* WE NOW ARE ON LOGICAL PAGES!! - using page table setup in dma_init */
161
        /* So we pass the buffer index value into the physical page offset */
162
        address = buf->idx << 12;
163
        length  = buf->used;
164
 
165
        DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
166
                  buf->context, buf->idx, length);
167
 
168
        if (buf->list == DRM_LIST_RECLAIM) {
169
                gamma_clear_next_buffer(dev);
170
                gamma_free_buffer(dev, buf);
171
                clear_bit(0, &dev->dma_flag);
172
                return -EINVAL;
173
        }
174
 
175
        if (!length) {
176
                DRM_ERROR("0 length buffer\n");
177
                gamma_clear_next_buffer(dev);
178
                gamma_free_buffer(dev, buf);
179
                clear_bit(0, &dev->dma_flag);
180
                return 0;
181
        }
182
 
183
        if (!gamma_dma_is_ready(dev)) {
184
                clear_bit(0, &dev->dma_flag);
185
                return -EBUSY;
186
        }
187
 
188
        if (buf->while_locked) {
189
                if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
190
                        DRM_ERROR("Dispatching buffer %d from pid %d"
191
                                  " \"while locked\", but no lock held\n",
192
                                  buf->idx, buf->pid);
193
                }
194
        } else {
195
                if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock,
196
                                              DRM_KERNEL_CONTEXT)) {
197
                        clear_bit(0, &dev->dma_flag);
198
                        return -EBUSY;
199
                }
200
        }
201
 
202
        if (dev->last_context != buf->context
203
            && !(dev->queuelist[buf->context]->flags
204
                 & _DRM_CONTEXT_PRESERVED)) {
205
                                /* PRE: dev->last_context != buf->context */
206
                if (DRM(context_switch)(dev, dev->last_context,
207
                                        buf->context)) {
208
                        DRM(clear_next_buffer)(dev);
209
                        DRM(free_buffer)(dev, buf);
210
                }
211
                retcode = -EBUSY;
212
                goto cleanup;
213
 
214
                                /* POST: we will wait for the context
215
                                   switch and will dispatch on a later call
216
                                   when dev->last_context == buf->context.
217
                                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
218
                                   TIME! */
219
        }
220
 
221
        gamma_clear_next_buffer(dev);
222
        buf->pending     = 1;
223
        buf->waiting     = 0;
224
        buf->list        = DRM_LIST_PEND;
225
#if DRM_DMA_HISTOGRAM
226
        buf->time_dispatched = get_cycles();
227
#endif
228
 
229
        /* WE NOW ARE ON LOGICAL PAGES!!! - overriding address */
230
        address = buf->idx << 12;
231
 
232
        gamma_dma_dispatch(dev, address, length);
233
        gamma_free_buffer(dev, dma->this_buffer);
234
        dma->this_buffer = buf;
235
 
236
        atomic_inc(&dev->counts[7]); /* _DRM_STAT_DMA */
237
        atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
238
 
239
        if (!buf->while_locked && !dev->context_flag && !locked) {
240
                if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
241
                                  DRM_KERNEL_CONTEXT)) {
242
                        DRM_ERROR("\n");
243
                }
244
        }
245
cleanup:
246
 
247
        clear_bit(0, &dev->dma_flag);
248
 
249
#if DRM_DMA_HISTOGRAM
250
        dma_stop = get_cycles();
251
        atomic_inc(&dev->histo.dma[gamma_histogram_slot(dma_stop - dma_start)]);
252
#endif
253
 
254
        return retcode;
255
}
256
 
257
static void gamma_dma_timer_bh(unsigned long dev)
258
{
259
        gamma_dma_schedule((drm_device_t *)dev, 0);
260
}
261
 
262
void gamma_dma_immediate_bh(void *dev)
263
{
264
        gamma_dma_schedule(dev, 0);
265
}
266
 
267
int gamma_dma_schedule(drm_device_t *dev, int locked)
268
{
269
        int              next;
270
        drm_queue_t      *q;
271
        drm_buf_t        *buf;
272
        int              retcode   = 0;
273
        int              processed = 0;
274
        int              missed;
275
        int              expire    = 20;
276
        drm_device_dma_t *dma      = dev->dma;
277
#if DRM_DMA_HISTOGRAM
278
        cycles_t         schedule_start;
279
#endif
280
 
281
        if (test_and_set_bit(0, &dev->interrupt_flag)) {
282
                                /* Not reentrant */
283
                atomic_inc(&dev->counts[10]); /* _DRM_STAT_MISSED */
284
                return -EBUSY;
285
        }
286
        missed = atomic_read(&dev->counts[10]);
287
 
288
#if DRM_DMA_HISTOGRAM
289
        schedule_start = get_cycles();
290
#endif
291
 
292
again:
293
        if (dev->context_flag) {
294
                clear_bit(0, &dev->interrupt_flag);
295
                return -EBUSY;
296
        }
297
        if (dma->next_buffer) {
298
                                /* Unsent buffer that was previously
299
                                   selected, but that couldn't be sent
300
                                   because the lock could not be obtained
301
                                   or the DMA engine wasn't ready.  Try
302
                                   again. */
303
                if (!(retcode = gamma_do_dma(dev, locked))) ++processed;
304
        } else {
305
                do {
306
                        next = gamma_select_queue(dev, gamma_dma_timer_bh);
307
                        if (next >= 0) {
308
                                q   = dev->queuelist[next];
309
                                buf = gamma_waitlist_get(&q->waitlist);
310
                                dma->next_buffer = buf;
311
                                dma->next_queue  = q;
312
                                if (buf && buf->list == DRM_LIST_RECLAIM) {
313
                                        gamma_clear_next_buffer(dev);
314
                                        gamma_free_buffer(dev, buf);
315
                                }
316
                        }
317
                } while (next >= 0 && !dma->next_buffer);
318
                if (dma->next_buffer) {
319
                        if (!(retcode = gamma_do_dma(dev, locked))) {
320
                                ++processed;
321
                        }
322
                }
323
        }
324
 
325
        if (--expire) {
326
                if (missed != atomic_read(&dev->counts[10])) {
327
                        if (gamma_dma_is_ready(dev)) goto again;
328
                }
329
                if (processed && gamma_dma_is_ready(dev)) {
330
                        processed = 0;
331
                        goto again;
332
                }
333
        }
334
 
335
        clear_bit(0, &dev->interrupt_flag);
336
 
337
#if DRM_DMA_HISTOGRAM
338
        atomic_inc(&dev->histo.schedule[gamma_histogram_slot(get_cycles()
339
                                                           - schedule_start)]);
340
#endif
341
        return retcode;
342
}
343
 
344
static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
345
{
346
        unsigned long     address;
347
        unsigned long     length;
348
        int               must_free = 0;
349
        int               retcode   = 0;
350
        int               i;
351
        int               idx;
352
        drm_buf_t         *buf;
353
        drm_buf_t         *last_buf = NULL;
354
        drm_device_dma_t  *dma      = dev->dma;
355
        DECLARE_WAITQUEUE(entry, current);
356
 
357
                                /* Turn off interrupt handling */
358
        while (test_and_set_bit(0, &dev->interrupt_flag)) {
359
                schedule();
360
                if (signal_pending(current)) return -EINTR;
361
        }
362
        if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
363
                while (!gamma_lock_take(&dev->lock.hw_lock->lock,
364
                                      DRM_KERNEL_CONTEXT)) {
365
                        schedule();
366
                        if (signal_pending(current)) {
367
                                clear_bit(0, &dev->interrupt_flag);
368
                                return -EINTR;
369
                        }
370
                }
371
                ++must_free;
372
        }
373
 
374
        for (i = 0; i < d->send_count; i++) {
375
                idx = d->send_indices[i];
376
                if (idx < 0 || idx >= dma->buf_count) {
377
                        DRM_ERROR("Index %d (of %d max)\n",
378
                                  d->send_indices[i], dma->buf_count - 1);
379
                        continue;
380
                }
381
                buf = dma->buflist[ idx ];
382
                if (buf->pid != current->pid) {
383
                        DRM_ERROR("Process %d using buffer owned by %d\n",
384
                                  current->pid, buf->pid);
385
                        retcode = -EINVAL;
386
                        goto cleanup;
387
                }
388
                if (buf->list != DRM_LIST_NONE) {
389
                        DRM_ERROR("Process %d using %d's buffer on list %d\n",
390
                                  current->pid, buf->pid, buf->list);
391
                        retcode = -EINVAL;
392
                        goto cleanup;
393
                }
394
                                /* This isn't a race condition on
395
                                   buf->list, since our concern is the
396
                                   buffer reclaim during the time the
397
                                   process closes the /dev/drm? handle, so
398
                                   it can't also be doing DMA. */
399
                buf->list         = DRM_LIST_PRIO;
400
                buf->used         = d->send_sizes[i];
401
                buf->context      = d->context;
402
                buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
403
                address           = (unsigned long)buf->address;
404
                length            = buf->used;
405
                if (!length) {
406
                        DRM_ERROR("0 length buffer\n");
407
                }
408
                if (buf->pending) {
409
                        DRM_ERROR("Sending pending buffer:"
410
                                  " buffer %d, offset %d\n",
411
                                  d->send_indices[i], i);
412
                        retcode = -EINVAL;
413
                        goto cleanup;
414
                }
415
                if (buf->waiting) {
416
                        DRM_ERROR("Sending waiting buffer:"
417
                                  " buffer %d, offset %d\n",
418
                                  d->send_indices[i], i);
419
                        retcode = -EINVAL;
420
                        goto cleanup;
421
                }
422
                buf->pending = 1;
423
 
424
                if (dev->last_context != buf->context
425
                    && !(dev->queuelist[buf->context]->flags
426
                         & _DRM_CONTEXT_PRESERVED)) {
427
                        add_wait_queue(&dev->context_wait, &entry);
428
                        current->state = TASK_INTERRUPTIBLE;
429
                                /* PRE: dev->last_context != buf->context */
430
                        DRM(context_switch)(dev, dev->last_context,
431
                                            buf->context);
432
                                /* POST: we will wait for the context
433
                                   switch and will dispatch on a later call
434
                                   when dev->last_context == buf->context.
435
                                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
436
                                   TIME! */
437
                        schedule();
438
                        current->state = TASK_RUNNING;
439
                        remove_wait_queue(&dev->context_wait, &entry);
440
                        if (signal_pending(current)) {
441
                                retcode = -EINTR;
442
                                goto cleanup;
443
                        }
444
                        if (dev->last_context != buf->context) {
445
                                DRM_ERROR("Context mismatch: %d %d\n",
446
                                          dev->last_context,
447
                                          buf->context);
448
                        }
449
                }
450
 
451
#if DRM_DMA_HISTOGRAM
452
                buf->time_queued     = get_cycles();
453
                buf->time_dispatched = buf->time_queued;
454
#endif
455
                gamma_dma_dispatch(dev, address, length);
456
                atomic_inc(&dev->counts[9]); /* _DRM_STAT_SPECIAL */
457
                atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
458
 
459
                if (last_buf) {
460
                        gamma_free_buffer(dev, last_buf);
461
                }
462
                last_buf = buf;
463
        }
464
 
465
 
466
cleanup:
467
        if (last_buf) {
468
                gamma_dma_ready(dev);
469
                gamma_free_buffer(dev, last_buf);
470
        }
471
 
472
        if (must_free && !dev->context_flag) {
473
                if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
474
                                  DRM_KERNEL_CONTEXT)) {
475
                        DRM_ERROR("\n");
476
                }
477
        }
478
        clear_bit(0, &dev->interrupt_flag);
479
        return retcode;
480
}
481
 
482
static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
483
{
484
        DECLARE_WAITQUEUE(entry, current);
485
        drm_buf_t         *last_buf = NULL;
486
        int               retcode   = 0;
487
        drm_device_dma_t  *dma      = dev->dma;
488
 
489
        if (d->flags & _DRM_DMA_BLOCK) {
490
                last_buf = dma->buflist[d->send_indices[d->send_count-1]];
491
                add_wait_queue(&last_buf->dma_wait, &entry);
492
        }
493
 
494
        if ((retcode = gamma_dma_enqueue(dev, d))) {
495
                if (d->flags & _DRM_DMA_BLOCK)
496
                        remove_wait_queue(&last_buf->dma_wait, &entry);
497
                return retcode;
498
        }
499
 
500
        gamma_dma_schedule(dev, 0);
501
 
502
        if (d->flags & _DRM_DMA_BLOCK) {
503
                DRM_DEBUG("%d waiting\n", current->pid);
504
                for (;;) {
505
                        current->state = TASK_INTERRUPTIBLE;
506
                        if (!last_buf->waiting && !last_buf->pending)
507
                                break; /* finished */
508
                        schedule();
509
                        if (signal_pending(current)) {
510
                                retcode = -EINTR; /* Can't restart */
511
                                break;
512
                        }
513
                }
514
                current->state = TASK_RUNNING;
515
                DRM_DEBUG("%d running\n", current->pid);
516
                remove_wait_queue(&last_buf->dma_wait, &entry);
517
                if (!retcode
518
                    || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
519
                        if (!waitqueue_active(&last_buf->dma_wait)) {
520
                                gamma_free_buffer(dev, last_buf);
521
                        }
522
                }
523
                if (retcode) {
524
                        DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d %d/%d\n",
525
                                  d->context,
526
                                  last_buf->waiting,
527
                                  last_buf->pending,
528
                                  (long)DRM_WAITCOUNT(dev, d->context),
529
                                  last_buf->idx,
530
                                  last_buf->list,
531
                                  last_buf->pid,
532
                                  current->pid);
533
                }
534
        }
535
        return retcode;
536
}
537
 
538
int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
539
              unsigned long arg)
540
{
541
        drm_file_t        *priv     = filp->private_data;
542
        drm_device_t      *dev      = priv->dev;
543
        drm_device_dma_t  *dma      = dev->dma;
544
        int               retcode   = 0;
545
        drm_dma_t         d;
546
 
547
        if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d)))
548
                return -EFAULT;
549
 
550
        if (d.send_count < 0 || d.send_count > dma->buf_count) {
551
                DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
552
                          current->pid, d.send_count, dma->buf_count);
553
                return -EINVAL;
554
        }
555
 
556
        if (d.request_count < 0 || d.request_count > dma->buf_count) {
557
                DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
558
                          current->pid, d.request_count, dma->buf_count);
559
                return -EINVAL;
560
        }
561
 
562
        if (d.send_count) {
563
                if (d.flags & _DRM_DMA_PRIORITY)
564
                        retcode = gamma_dma_priority(dev, &d);
565
                else
566
                        retcode = gamma_dma_send_buffers(dev, &d);
567
        }
568
 
569
        d.granted_count = 0;
570
 
571
        if (!retcode && d.request_count) {
572
                retcode = gamma_dma_get_buffers(dev, &d);
573
        }
574
 
575
        DRM_DEBUG("%d returning, granted = %d\n",
576
                  current->pid, d.granted_count);
577
        if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
578
                return -EFAULT;
579
 
580
        return retcode;
581
}
582
 
583
/* =============================================================
584
 * DMA initialization, cleanup
585
 */
586
 
587
static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init )
588
{
589
        drm_gamma_private_t *dev_priv;
590
        drm_device_dma_t    *dma = dev->dma;
591
        drm_buf_t           *buf;
592
        int i;
593
        struct list_head    *list;
594
        unsigned long       *pgt;
595
 
596
        DRM_DEBUG( "%s\n", __FUNCTION__ );
597
 
598
        dev_priv = DRM(alloc)( sizeof(drm_gamma_private_t),
599
                                                        DRM_MEM_DRIVER );
600
        if ( !dev_priv )
601
                return -ENOMEM;
602
 
603
        dev->dev_private = (void *)dev_priv;
604
 
605
        memset( dev_priv, 0, sizeof(drm_gamma_private_t) );
606
 
607
        list_for_each(list, &dev->maplist->head) {
608
                #warning list_entry() is needed here
609
                drm_map_list_t *r_list = (drm_map_list_t *)list;
610
                if( r_list->map &&
611
                    r_list->map->type == _DRM_SHM &&
612
                    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
613
                        dev_priv->sarea = r_list->map;
614
                        break;
615
                }
616
        }
617
 
618
        DRM_FIND_MAP( dev_priv->mmio0, init->mmio0 );
619
        DRM_FIND_MAP( dev_priv->mmio1, init->mmio1 );
620
        DRM_FIND_MAP( dev_priv->mmio2, init->mmio2 );
621
        DRM_FIND_MAP( dev_priv->mmio3, init->mmio3 );
622
 
623
        dev_priv->sarea_priv = (drm_gamma_sarea_t *)
624
                ((u8 *)dev_priv->sarea->handle +
625
                 init->sarea_priv_offset);
626
 
627
        if (init->pcimode) {
628
                buf = dma->buflist[GLINT_DRI_BUF_COUNT];
629
                pgt = buf->address;
630
 
631
                for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
632
                        buf = dma->buflist[i];
633
                        *pgt = virt_to_phys((void*)buf->address) | 0x07;
634
                        pgt++;
635
                }
636
 
637
                buf = dma->buflist[GLINT_DRI_BUF_COUNT];
638
        } else {
639
                DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
640
 
641
                DRM_IOREMAP( dev_priv->buffers, dev );
642
 
643
                buf = dma->buflist[GLINT_DRI_BUF_COUNT];
644
                pgt = buf->address;
645
 
646
                for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
647
                        buf = dma->buflist[i];
648
                        *pgt = (unsigned long)buf->address + 0x07;
649
                        pgt++;
650
                }
651
 
652
                buf = dma->buflist[GLINT_DRI_BUF_COUNT];
653
 
654
                while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1) cpu_relax();
655
                GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe) ;
656
        }
657
        while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2); cpu_relax();
658
        GAMMA_WRITE( GAMMA_PAGETABLEADDR, virt_to_phys((void*)buf->address) );
659
        GAMMA_WRITE( GAMMA_PAGETABLELENGTH, 2 );
660
 
661
        return 0;
662
}
663
 
664
int gamma_do_cleanup_dma( drm_device_t *dev )
665
{
666
        DRM_DEBUG( "%s\n", __FUNCTION__ );
667
 
668
        if ( dev->dev_private ) {
669
                drm_gamma_private_t *dev_priv = dev->dev_private;
670
 
671
                DRM_IOREMAPFREE( dev_priv->buffers, dev );
672
 
673
                DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t),
674
                           DRM_MEM_DRIVER );
675
                dev->dev_private = NULL;
676
        }
677
 
678
        return 0;
679
}
680
 
681
int gamma_dma_init( struct inode *inode, struct file *filp,
682
                  unsigned int cmd, unsigned long arg )
683
{
684
        drm_file_t *priv = filp->private_data;
685
        drm_device_t *dev = priv->dev;
686
        drm_gamma_init_t init;
687
 
688
        if ( copy_from_user( &init, (drm_gamma_init_t *)arg, sizeof(init) ) )
689
                return -EFAULT;
690
 
691
        switch ( init.func ) {
692
        case GAMMA_INIT_DMA:
693
                return gamma_do_init_dma( dev, &init );
694
        case GAMMA_CLEANUP_DMA:
695
                return gamma_do_cleanup_dma( dev );
696
        }
697
 
698
        return -EINVAL;
699
}
700
 
701
static int gamma_do_copy_dma( drm_device_t *dev, drm_gamma_copy_t *copy )
702
{
703
        drm_device_dma_t    *dma = dev->dma;
704
        unsigned int        *screenbuf;
705
 
706
        DRM_DEBUG( "%s\n", __FUNCTION__ );
707
 
708
        /* We've DRM_RESTRICTED this DMA buffer */
709
 
710
        screenbuf = dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ]->address;
711
 
712
#if 0
713
        *buffer++ = 0x180;      /* Tag (FilterMode) */
714
        *buffer++ = 0x200;      /* Allow FBColor through */
715
        *buffer++ = 0x53B;      /* Tag */
716
        *buffer++ = copy->Pitch;
717
        *buffer++ = 0x53A;      /* Tag */
718
        *buffer++ = copy->SrcAddress;
719
        *buffer++ = 0x539;      /* Tag */
720
        *buffer++ = copy->WidthHeight; /* Initiates transfer */
721
        *buffer++ = 0x53C;      /* Tag - DMAOutputAddress */
722
        *buffer++ = virt_to_phys((void*)screenbuf);
723
        *buffer++ = 0x53D;      /* Tag - DMAOutputCount */
724
        *buffer++ = copy->Count; /* Reads HostOutFifo BLOCKS until ..*/
725
 
726
        /* Data now sitting in dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ] */
727
        /* Now put it back to the screen */
728
 
729
        *buffer++ = 0x180;      /* Tag (FilterMode) */
730
        *buffer++ = 0x400;      /* Allow Sync through */
731
        *buffer++ = 0x538;      /* Tag - DMARectangleReadTarget */
732
        *buffer++ = 0x155;      /* FBSourceData | count */
733
        *buffer++ = 0x537;      /* Tag */
734
        *buffer++ = copy->Pitch;
735
        *buffer++ = 0x536;      /* Tag */
736
        *buffer++ = copy->DstAddress;
737
        *buffer++ = 0x535;      /* Tag */
738
        *buffer++ = copy->WidthHeight; /* Initiates transfer */
739
        *buffer++ = 0x530;      /* Tag - DMAAddr */
740
        *buffer++ = virt_to_phys((void*)screenbuf);
741
        *buffer++ = 0x531;
742
        *buffer++ = copy->Count; /* initiates DMA transfer of color data */
743
#endif
744
 
745
        /* need to dispatch it now */
746
 
747
        return 0;
748
}
749
 
750
int gamma_dma_copy( struct inode *inode, struct file *filp,
751
                  unsigned int cmd, unsigned long arg )
752
{
753
        drm_file_t *priv = filp->private_data;
754
        drm_device_t *dev = priv->dev;
755
        drm_gamma_copy_t copy;
756
 
757
        if ( copy_from_user( &copy, (drm_gamma_copy_t *)arg, sizeof(copy) ) )
758
                return -EFAULT;
759
 
760
        return gamma_do_copy_dma( dev, &copy );
761
}
762
 
763
/* =============================================================
764
 * Per Context SAREA Support
765
 */
766
 
767
int gamma_getsareactx(struct inode *inode, struct file *filp,
768
                     unsigned int cmd, unsigned long arg)
769
{
770
        drm_file_t      *priv   = filp->private_data;
771
        drm_device_t    *dev    = priv->dev;
772
        drm_ctx_priv_map_t request;
773
        drm_map_t *map;
774
 
775
        if (copy_from_user(&request,
776
                           (drm_ctx_priv_map_t *)arg,
777
                           sizeof(request)))
778
                return -EFAULT;
779
 
780
        down(&dev->struct_sem);
781
        if ((int)request.ctx_id >= dev->max_context) {
782
                up(&dev->struct_sem);
783
                return -EINVAL;
784
        }
785
 
786
        map = dev->context_sareas[request.ctx_id];
787
        up(&dev->struct_sem);
788
 
789
        request.handle = map->handle;
790
        if (copy_to_user((drm_ctx_priv_map_t *)arg, &request, sizeof(request)))
791
                return -EFAULT;
792
        return 0;
793
}
794
 
795
int gamma_setsareactx(struct inode *inode, struct file *filp,
796
                     unsigned int cmd, unsigned long arg)
797
{
798
        drm_file_t      *priv   = filp->private_data;
799
        drm_device_t    *dev    = priv->dev;
800
        drm_ctx_priv_map_t request;
801
        drm_map_t *map = NULL;
802
        drm_map_list_t *r_list;
803
        struct list_head *list;
804
 
805
        if (copy_from_user(&request,
806
                           (drm_ctx_priv_map_t *)arg,
807
                           sizeof(request)))
808
                return -EFAULT;
809
 
810
        down(&dev->struct_sem);
811
        r_list = NULL;
812
        list_for_each(list, &dev->maplist->head) {
813
                r_list = (drm_map_list_t *)list;
814
                if(r_list->map &&
815
                   r_list->map->handle == request.handle) break;
816
        }
817
        if (list == &(dev->maplist->head)) {
818
                up(&dev->struct_sem);
819
                return -EINVAL;
820
        }
821
        map = r_list->map;
822
        up(&dev->struct_sem);
823
 
824
        if (!map) return -EINVAL;
825
 
826
        down(&dev->struct_sem);
827
        if ((int)request.ctx_id >= dev->max_context) {
828
                up(&dev->struct_sem);
829
                return -EINVAL;
830
        }
831
        dev->context_sareas[request.ctx_id] = map;
832
        up(&dev->struct_sem);
833
        return 0;
834
}
835
 
836
/* drm_dma.h hooks
837
*/
838
void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
839
}
840
 
841
void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
842
}
843
 
844
void DRM(driver_irq_uninstall)( drm_device_t *dev ) {
845
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.