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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* dma.c -- DMA IOCTL and function support -*- linux-c -*-
2
 * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.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
 * 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@valinuxa.com>
29
 *
30
 */
31
 
32
#define __NO_VERSION__
33
#include "drmP.h"
34
 
35
#include <linux/interrupt.h>    /* For task queue support */
36
 
37
void drm_dma_setup(drm_device_t *dev)
38
{
39
        int i;
40
 
41
        if (!(dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER))) {
42
                printk(KERN_ERR "drm_dma_setup: can't drm_alloc dev->dma");
43
                return;
44
        }
45
        memset(dev->dma, 0, sizeof(*dev->dma));
46
        for (i = 0; i <= DRM_MAX_ORDER; i++)
47
                memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
48
}
49
 
50
void drm_dma_takedown(drm_device_t *dev)
51
{
52
        drm_device_dma_t  *dma = dev->dma;
53
        int               i, j;
54
 
55
        if (!dma) return;
56
 
57
                                /* Clear dma buffers */
58
        for (i = 0; i <= DRM_MAX_ORDER; i++) {
59
                if (dma->bufs[i].seg_count) {
60
                        DRM_DEBUG("order %d: buf_count = %d,"
61
                                  " seg_count = %d\n",
62
                                  i,
63
                                  dma->bufs[i].buf_count,
64
                                  dma->bufs[i].seg_count);
65
                        for (j = 0; j < dma->bufs[i].seg_count; j++) {
66
                                drm_free_pages(dma->bufs[i].seglist[j],
67
                                               dma->bufs[i].page_order,
68
                                               DRM_MEM_DMA);
69
                        }
70
                        drm_free(dma->bufs[i].seglist,
71
                                 dma->bufs[i].seg_count
72
                                 * sizeof(*dma->bufs[0].seglist),
73
                                 DRM_MEM_SEGS);
74
                }
75
                if(dma->bufs[i].buf_count) {
76
                        for(j = 0; j < dma->bufs[i].buf_count; j++) {
77
                           if(dma->bufs[i].buflist[j].dev_private) {
78
                              drm_free(dma->bufs[i].buflist[j].dev_private,
79
                                       dma->bufs[i].buflist[j].dev_priv_size,
80
                                       DRM_MEM_BUFS);
81
                           }
82
                        }
83
                        drm_free(dma->bufs[i].buflist,
84
                                 dma->bufs[i].buf_count *
85
                                 sizeof(*dma->bufs[0].buflist),
86
                                 DRM_MEM_BUFS);
87
                        drm_freelist_destroy(&dma->bufs[i].freelist);
88
                }
89
        }
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
        drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
103
        dev->dma = NULL;
104
}
105
 
106
#if DRM_DMA_HISTOGRAM
107
/* This is slow, but is useful for debugging. */
108
int drm_histogram_slot(unsigned long count)
109
{
110
        int value = DRM_DMA_HISTOGRAM_INITIAL;
111
        int slot;
112
 
113
        for (slot = 0;
114
             slot < DRM_DMA_HISTOGRAM_SLOTS;
115
             ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
116
                if (count < value) return slot;
117
        }
118
        return DRM_DMA_HISTOGRAM_SLOTS - 1;
119
}
120
 
121
void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
122
{
123
        cycles_t queued_to_dispatched;
124
        cycles_t dispatched_to_completed;
125
        cycles_t completed_to_freed;
126
        int      q2d, d2c, c2f, q2c, q2f;
127
 
128
        if (buf->time_queued) {
129
                queued_to_dispatched    = (buf->time_dispatched
130
                                           - buf->time_queued);
131
                dispatched_to_completed = (buf->time_completed
132
                                           - buf->time_dispatched);
133
                completed_to_freed      = (buf->time_freed
134
                                           - buf->time_completed);
135
 
136
                q2d = drm_histogram_slot(queued_to_dispatched);
137
                d2c = drm_histogram_slot(dispatched_to_completed);
138
                c2f = drm_histogram_slot(completed_to_freed);
139
 
140
                q2c = drm_histogram_slot(queued_to_dispatched
141
                                         + dispatched_to_completed);
142
                q2f = drm_histogram_slot(queued_to_dispatched
143
                                         + dispatched_to_completed
144
                                         + completed_to_freed);
145
 
146
                atomic_inc(&dev->histo.total);
147
                atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
148
                atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
149
                atomic_inc(&dev->histo.completed_to_freed[c2f]);
150
 
151
                atomic_inc(&dev->histo.queued_to_completed[q2c]);
152
                atomic_inc(&dev->histo.queued_to_freed[q2f]);
153
 
154
        }
155
        buf->time_queued     = 0;
156
        buf->time_dispatched = 0;
157
        buf->time_completed  = 0;
158
        buf->time_freed      = 0;
159
}
160
#endif
161
 
162
void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
163
{
164
        drm_device_dma_t *dma = dev->dma;
165
 
166
        if (!buf) return;
167
 
168
        buf->waiting  = 0;
169
        buf->pending  = 0;
170
        buf->pid      = 0;
171
        buf->used     = 0;
172
#if DRM_DMA_HISTOGRAM
173
        buf->time_completed = get_cycles();
174
#endif
175
        if (waitqueue_active(&buf->dma_wait)) {
176
                wake_up_interruptible(&buf->dma_wait);
177
        } else {
178
                                /* If processes are waiting, the last one
179
                                   to wake will put the buffer on the free
180
                                   list.  If no processes are waiting, we
181
                                   put the buffer on the freelist here. */
182
                drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
183
        }
184
}
185
 
186
void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
187
{
188
        drm_device_dma_t *dma = dev->dma;
189
        int              i;
190
 
191
        if (!dma) return;
192
        for (i = 0; i < dma->buf_count; i++) {
193
                if (dma->buflist[i]->pid == pid) {
194
                        switch (dma->buflist[i]->list) {
195
                        case DRM_LIST_NONE:
196
                                drm_free_buffer(dev, dma->buflist[i]);
197
                                break;
198
                        case DRM_LIST_WAIT:
199
                                dma->buflist[i]->list = DRM_LIST_RECLAIM;
200
                                break;
201
                        default:
202
                                /* Buffer already on hardware. */
203
                                break;
204
                        }
205
                }
206
        }
207
}
208
 
209
int drm_context_switch(drm_device_t *dev, int old, int new)
210
{
211
        char        buf[64];
212
        drm_queue_t *q;
213
 
214
        atomic_inc(&dev->total_ctx);
215
 
216
        if (test_and_set_bit(0, &dev->context_flag)) {
217
                DRM_ERROR("Reentering -- FIXME\n");
218
                return -EBUSY;
219
        }
220
 
221
#if DRM_DMA_HISTOGRAM
222
        dev->ctx_start = get_cycles();
223
#endif
224
 
225
        DRM_DEBUG("Context switch from %d to %d\n", old, new);
226
 
227
        if (new >= dev->queue_count) {
228
                clear_bit(0, &dev->context_flag);
229
                return -EINVAL;
230
        }
231
 
232
        if (new == dev->last_context) {
233
                clear_bit(0, &dev->context_flag);
234
                return 0;
235
        }
236
 
237
        q = dev->queuelist[new];
238
        atomic_inc(&q->use_count);
239
        if (atomic_read(&q->use_count) == 1) {
240
                atomic_dec(&q->use_count);
241
                clear_bit(0, &dev->context_flag);
242
                return -EINVAL;
243
        }
244
 
245
        if (drm_flags & DRM_FLAG_NOCTX) {
246
                drm_context_switch_complete(dev, new);
247
        } else {
248
                sprintf(buf, "C %d %d\n", old, new);
249
                drm_write_string(dev, buf);
250
        }
251
 
252
        atomic_dec(&q->use_count);
253
 
254
        return 0;
255
}
256
 
257
int drm_context_switch_complete(drm_device_t *dev, int new)
258
{
259
        drm_device_dma_t *dma = dev->dma;
260
 
261
        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
262
        dev->last_switch  = jiffies;
263
 
264
        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
265
                DRM_ERROR("Lock isn't held after context switch\n");
266
        }
267
 
268
        if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
269
                if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
270
                                  DRM_KERNEL_CONTEXT)) {
271
                        DRM_ERROR("Cannot free lock\n");
272
                }
273
        }
274
 
275
#if DRM_DMA_HISTOGRAM
276
        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
277
                                                      - dev->ctx_start)]);
278
 
279
#endif
280
        clear_bit(0, &dev->context_flag);
281
        wake_up_interruptible(&dev->context_wait);
282
 
283
        return 0;
284
}
285
 
286
void drm_clear_next_buffer(drm_device_t *dev)
287
{
288
        drm_device_dma_t *dma = dev->dma;
289
 
290
        dma->next_buffer = NULL;
291
        if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
292
                wake_up_interruptible(&dma->next_queue->flush_queue);
293
        }
294
        dma->next_queue  = NULL;
295
}
296
 
297
 
298
int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long))
299
{
300
        int        i;
301
        int        candidate = -1;
302
        int        j         = jiffies;
303
 
304
        if (!dev) {
305
                DRM_ERROR("No device\n");
306
                return -1;
307
        }
308
        if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
309
                                /* This only happens between the time the
310
                                   interrupt is initialized and the time
311
                                   the queues are initialized. */
312
                return -1;
313
        }
314
 
315
                                /* Doing "while locked" DMA? */
316
        if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
317
                return DRM_KERNEL_CONTEXT;
318
        }
319
 
320
                                /* If there are buffers on the last_context
321
                                   queue, and we have not been executing
322
                                   this context very long, continue to
323
                                   execute this context. */
324
        if (dev->last_switch <= j
325
            && dev->last_switch + DRM_TIME_SLICE > j
326
            && DRM_WAITCOUNT(dev, dev->last_context)) {
327
                return dev->last_context;
328
        }
329
 
330
                                /* Otherwise, find a candidate */
331
        for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
332
                if (DRM_WAITCOUNT(dev, i)) {
333
                        candidate = dev->last_checked = i;
334
                        break;
335
                }
336
        }
337
 
338
        if (candidate < 0) {
339
                for (i = 0; i < dev->queue_count; i++) {
340
                        if (DRM_WAITCOUNT(dev, i)) {
341
                                candidate = dev->last_checked = i;
342
                                break;
343
                        }
344
                }
345
        }
346
 
347
        if (wrapper
348
            && candidate >= 0
349
            && candidate != dev->last_context
350
            && dev->last_switch <= j
351
            && dev->last_switch + DRM_TIME_SLICE > j) {
352
                if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
353
                        del_timer(&dev->timer);
354
                        dev->timer.function = wrapper;
355
                        dev->timer.data     = (unsigned long)dev;
356
                        dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
357
                        add_timer(&dev->timer);
358
                }
359
                return -1;
360
        }
361
 
362
        return candidate;
363
}
364
 
365
 
366
int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
367
{
368
        int               i;
369
        drm_queue_t       *q;
370
        drm_buf_t         *buf;
371
        int               idx;
372
        int               while_locked = 0;
373
        drm_device_dma_t  *dma = dev->dma;
374
        DECLARE_WAITQUEUE(entry, current);
375
 
376
        DRM_DEBUG("%d\n", d->send_count);
377
 
378
        if (d->flags & _DRM_DMA_WHILE_LOCKED) {
379
                int context = dev->lock.hw_lock->lock;
380
 
381
                if (!_DRM_LOCK_IS_HELD(context)) {
382
                        DRM_ERROR("No lock held during \"while locked\""
383
                                  " request\n");
384
                        return -EINVAL;
385
                }
386
                if (d->context != _DRM_LOCKING_CONTEXT(context)
387
                    && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
388
                        DRM_ERROR("Lock held by %d while %d makes"
389
                                  " \"while locked\" request\n",
390
                                  _DRM_LOCKING_CONTEXT(context),
391
                                  d->context);
392
                        return -EINVAL;
393
                }
394
                q = dev->queuelist[DRM_KERNEL_CONTEXT];
395
                while_locked = 1;
396
        } else {
397
                q = dev->queuelist[d->context];
398
        }
399
 
400
 
401
        atomic_inc(&q->use_count);
402
        if (atomic_read(&q->block_write)) {
403
                add_wait_queue(&q->write_queue, &entry);
404
                atomic_inc(&q->block_count);
405
                for (;;) {
406
                        current->state = TASK_INTERRUPTIBLE;
407
                        if (!atomic_read(&q->block_write)) break;
408
                        schedule();
409
                        if (signal_pending(current)) {
410
                                atomic_dec(&q->use_count);
411
                                remove_wait_queue(&q->write_queue, &entry);
412
                                return -EINTR;
413
                        }
414
                }
415
                atomic_dec(&q->block_count);
416
                current->state = TASK_RUNNING;
417
                remove_wait_queue(&q->write_queue, &entry);
418
        }
419
 
420
        for (i = 0; i < d->send_count; i++) {
421
                idx = d->send_indices[i];
422
                if (idx < 0 || idx >= dma->buf_count) {
423
                        atomic_dec(&q->use_count);
424
                        DRM_ERROR("Index %d (of %d max)\n",
425
                                  d->send_indices[i], dma->buf_count - 1);
426
                        return -EINVAL;
427
                }
428
                buf = dma->buflist[ idx ];
429
                if (buf->pid != current->pid) {
430
                        atomic_dec(&q->use_count);
431
                        DRM_ERROR("Process %d using buffer owned by %d\n",
432
                                  current->pid, buf->pid);
433
                        return -EINVAL;
434
                }
435
                if (buf->list != DRM_LIST_NONE) {
436
                        atomic_dec(&q->use_count);
437
                        DRM_ERROR("Process %d using buffer %d on list %d\n",
438
                                  current->pid, buf->idx, buf->list);
439
                }
440
                buf->used         = d->send_sizes[i];
441
                buf->while_locked = while_locked;
442
                buf->context      = d->context;
443
                if (!buf->used) {
444
                        DRM_ERROR("Queueing 0 length buffer\n");
445
                }
446
                if (buf->pending) {
447
                        atomic_dec(&q->use_count);
448
                        DRM_ERROR("Queueing pending buffer:"
449
                                  " buffer %d, offset %d\n",
450
                                  d->send_indices[i], i);
451
                        return -EINVAL;
452
                }
453
                if (buf->waiting) {
454
                        atomic_dec(&q->use_count);
455
                        DRM_ERROR("Queueing waiting buffer:"
456
                                  " buffer %d, offset %d\n",
457
                                  d->send_indices[i], i);
458
                        return -EINVAL;
459
                }
460
                buf->waiting = 1;
461
                if (atomic_read(&q->use_count) == 1
462
                    || atomic_read(&q->finalization)) {
463
                        drm_free_buffer(dev, buf);
464
                } else {
465
                        drm_waitlist_put(&q->waitlist, buf);
466
                        atomic_inc(&q->total_queued);
467
                }
468
        }
469
        atomic_dec(&q->use_count);
470
 
471
        return 0;
472
}
473
 
474
static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
475
                                        int order)
476
{
477
        int               i;
478
        drm_buf_t         *buf;
479
        drm_device_dma_t  *dma = dev->dma;
480
 
481
        for (i = d->granted_count; i < d->request_count; i++) {
482
                buf = drm_freelist_get(&dma->bufs[order].freelist,
483
                                       d->flags & _DRM_DMA_WAIT);
484
                if (!buf) break;
485
                if (buf->pending || buf->waiting) {
486
                        DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
487
                                  buf->idx,
488
                                  buf->pid,
489
                                  buf->waiting,
490
                                  buf->pending);
491
                }
492
                buf->pid     = current->pid;
493
                if (copy_to_user(&d->request_indices[i],
494
                                 &buf->idx,
495
                                 sizeof(buf->idx)))
496
                        return -EFAULT;
497
 
498
                if (copy_to_user(&d->request_sizes[i],
499
                                 &buf->total,
500
                                 sizeof(buf->total)))
501
                        return -EFAULT;
502
 
503
                ++d->granted_count;
504
        }
505
        return 0;
506
}
507
 
508
 
509
int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
510
{
511
        int               order;
512
        int               retcode = 0;
513
        int               tmp_order;
514
 
515
        order = drm_order(dma->request_size);
516
 
517
        dma->granted_count = 0;
518
        retcode            = drm_dma_get_buffers_of_order(dev, dma, order);
519
 
520
        if (dma->granted_count < dma->request_count
521
            && (dma->flags & _DRM_DMA_SMALLER_OK)) {
522
                for (tmp_order = order - 1;
523
                     !retcode
524
                             && dma->granted_count < dma->request_count
525
                             && tmp_order >= DRM_MIN_ORDER;
526
                     --tmp_order) {
527
 
528
                        retcode = drm_dma_get_buffers_of_order(dev, dma,
529
                                                               tmp_order);
530
                }
531
        }
532
 
533
        if (dma->granted_count < dma->request_count
534
            && (dma->flags & _DRM_DMA_LARGER_OK)) {
535
                for (tmp_order = order + 1;
536
                     !retcode
537
                             && dma->granted_count < dma->request_count
538
                             && tmp_order <= DRM_MAX_ORDER;
539
                     ++tmp_order) {
540
 
541
                        retcode = drm_dma_get_buffers_of_order(dev, dma,
542
                                                               tmp_order);
543
                }
544
        }
545
        return 0;
546
}

powered by: WebSVN 2.1.0

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