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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* drm_bufs.h -- Generic buffer template -*- linux-c -*-
2
 * Created: Thu Nov 23 03:10:50 2000 by gareth@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
 
32
#include <linux/vmalloc.h>
33
#include "drmP.h"
34
 
35
#ifndef __HAVE_PCI_DMA
36
#define __HAVE_PCI_DMA          0
37
#endif
38
 
39
#ifndef __HAVE_SG
40
#define __HAVE_SG               0
41
#endif
42
 
43
#ifndef DRIVER_BUF_PRIV_T
44
#define DRIVER_BUF_PRIV_T               u32
45
#endif
46
#ifndef DRIVER_AGP_BUFFERS_MAP
47
#if __HAVE_AGP && __HAVE_DMA
48
#error "You must define DRIVER_AGP_BUFFERS_MAP()"
49
#else
50
#define DRIVER_AGP_BUFFERS_MAP( dev )   NULL
51
#endif
52
#endif
53
 
54
/*
55
 * Compute order.  Can be made faster.
56
 */
57
int DRM(order)( unsigned long size )
58
{
59
        int order;
60
        unsigned long tmp;
61
 
62
        for ( order = 0, tmp = size ; tmp >>= 1 ; ++order );
63
 
64
        if ( size & ~(1 << order) )
65
                ++order;
66
 
67
        return order;
68
}
69
 
70
int DRM(addmap)( struct inode *inode, struct file *filp,
71
                 unsigned int cmd, unsigned long arg )
72
{
73
        drm_file_t *priv = filp->private_data;
74
        drm_device_t *dev = priv->dev;
75
        drm_map_t *map;
76
        drm_map_list_t *list;
77
 
78
        if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
79
 
80
        map = DRM(alloc)( sizeof(*map), DRM_MEM_MAPS );
81
        if ( !map )
82
                return -ENOMEM;
83
 
84
        if ( copy_from_user( map, (drm_map_t *)arg, sizeof(*map) ) ) {
85
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
86
                return -EFAULT;
87
        }
88
 
89
        /* Only allow shared memory to be removable since we only keep enough
90
         * book keeping information about shared memory to allow for removal
91
         * when processes fork.
92
         */
93
        if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) {
94
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
95
                return -EINVAL;
96
        }
97
        DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
98
                   map->offset, map->size, map->type );
99
        if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) {
100
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
101
                return -EINVAL;
102
        }
103
        map->mtrr   = -1;
104
        map->handle = 0;
105
 
106
        switch ( map->type ) {
107
        case _DRM_REGISTERS:
108
        case _DRM_FRAME_BUFFER:
109
#if !defined(__sparc__) && !defined(__alpha__)
110
                if ( map->offset + map->size < map->offset ||
111
                     map->offset < virt_to_phys(high_memory) ) {
112
                        DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
113
                        return -EINVAL;
114
                }
115
#endif
116
#ifdef __alpha__
117
                map->offset += dev->hose->mem_space->start;
118
#endif
119
#if __REALLY_HAVE_MTRR
120
                if ( map->type == _DRM_FRAME_BUFFER ||
121
                     (map->flags & _DRM_WRITE_COMBINING) ) {
122
                        map->mtrr = mtrr_add( map->offset, map->size,
123
                                              MTRR_TYPE_WRCOMB, 1 );
124
                }
125
#endif
126
                map->handle = DRM(ioremap)( map->offset, map->size, dev );
127
                break;
128
 
129
        case _DRM_SHM:
130
                map->handle = vmalloc_32(map->size);
131
                DRM_DEBUG( "%ld %d %p\n",
132
                           map->size, DRM(order)( map->size ), map->handle );
133
                if ( !map->handle ) {
134
                        DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
135
                        return -ENOMEM;
136
                }
137
                map->offset = (unsigned long)map->handle;
138
                if ( map->flags & _DRM_CONTAINS_LOCK ) {
139
                        dev->sigdata.lock =
140
                        dev->lock.hw_lock = map->handle; /* Pointer to lock */
141
                }
142
                break;
143
#if __REALLY_HAVE_AGP
144
        case _DRM_AGP:
145
#ifdef __alpha__
146
                map->offset += dev->hose->mem_space->start;
147
#endif
148
                map->offset = map->offset + dev->agp->base;
149
                map->mtrr   = dev->agp->agp_mtrr; /* for getmap */
150
                break;
151
#endif
152
        case _DRM_SCATTER_GATHER:
153
                if (!dev->sg) {
154
                        DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
155
                        return -EINVAL;
156
                }
157
                map->offset = map->offset + dev->sg->handle;
158
                break;
159
 
160
        default:
161
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
162
                return -EINVAL;
163
        }
164
 
165
        list = DRM(alloc)(sizeof(*list), DRM_MEM_MAPS);
166
        if(!list) {
167
                DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
168
                return -EINVAL;
169
        }
170
        memset(list, 0, sizeof(*list));
171
        list->map = map;
172
 
173
        down(&dev->struct_sem);
174
        list_add(&list->head, &dev->maplist->head);
175
        up(&dev->struct_sem);
176
 
177
        if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) )
178
                return -EFAULT;
179
        if ( map->type != _DRM_SHM ) {
180
                if ( copy_to_user( &((drm_map_t *)arg)->handle,
181
                                   &map->offset,
182
                                   sizeof(map->offset) ) )
183
                        return -EFAULT;
184
        }
185
        return 0;
186
}
187
 
188
 
189
/* Remove a map private from list and deallocate resources if the mapping
190
 * isn't in use.
191
 */
192
 
193
int DRM(rmmap)(struct inode *inode, struct file *filp,
194
               unsigned int cmd, unsigned long arg)
195
{
196
        drm_file_t      *priv   = filp->private_data;
197
        drm_device_t    *dev    = priv->dev;
198
        struct list_head *list;
199
        drm_map_list_t *r_list = NULL;
200
        drm_vma_entry_t *pt, *prev;
201
        drm_map_t *map;
202
        drm_map_t request;
203
        int found_maps = 0;
204
 
205
        if (copy_from_user(&request, (drm_map_t *)arg,
206
                           sizeof(request))) {
207
                return -EFAULT;
208
        }
209
 
210
        down(&dev->struct_sem);
211
        list = &dev->maplist->head;
212
        list_for_each(list, &dev->maplist->head) {
213
                r_list = (drm_map_list_t *) list;
214
 
215
                if(r_list->map &&
216
                   r_list->map->handle == request.handle &&
217
                   r_list->map->flags & _DRM_REMOVABLE) break;
218
        }
219
 
220
        /* List has wrapped around to the head pointer, or its empty we didn't
221
         * find anything.
222
         */
223
        if(list == (&dev->maplist->head)) {
224
                up(&dev->struct_sem);
225
                return -EINVAL;
226
        }
227
        map = r_list->map;
228
        list_del(list);
229
        DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
230
 
231
        for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
232
                if (pt->vma->vm_private_data == map) found_maps++;
233
        }
234
 
235
        if(!found_maps) {
236
                switch (map->type) {
237
                case _DRM_REGISTERS:
238
                case _DRM_FRAME_BUFFER:
239
#if __REALLY_HAVE_MTRR
240
                        if (map->mtrr >= 0) {
241
                                int retcode;
242
                                retcode = mtrr_del(map->mtrr,
243
                                                   map->offset,
244
                                                   map->size);
245
                                DRM_DEBUG("mtrr_del = %d\n", retcode);
246
                        }
247
#endif
248
                        DRM(ioremapfree)(map->handle, map->size, dev);
249
                        break;
250
                case _DRM_SHM:
251
                        vfree(map->handle);
252
                        break;
253
                case _DRM_AGP:
254
                case _DRM_SCATTER_GATHER:
255
                        break;
256
                }
257
                DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
258
        }
259
        up(&dev->struct_sem);
260
        return 0;
261
}
262
 
263
#if __HAVE_DMA
264
 
265
 
266
static void DRM(cleanup_buf_error)(drm_buf_entry_t *entry)
267
{
268
        int i;
269
 
270
        if (entry->seg_count) {
271
                for (i = 0; i < entry->seg_count; i++) {
272
                        DRM(free_pages)(entry->seglist[i],
273
                                        entry->page_order,
274
                                        DRM_MEM_DMA);
275
                }
276
                DRM(free)(entry->seglist,
277
                          entry->seg_count *
278
                          sizeof(*entry->seglist),
279
                          DRM_MEM_SEGS);
280
 
281
                entry->seg_count = 0;
282
        }
283
 
284
        if(entry->buf_count) {
285
                for(i = 0; i < entry->buf_count; i++) {
286
                        if(entry->buflist[i].dev_private) {
287
                                DRM(free)(entry->buflist[i].dev_private,
288
                                          entry->buflist[i].dev_priv_size,
289
                                          DRM_MEM_BUFS);
290
                        }
291
                }
292
                DRM(free)(entry->buflist,
293
                          entry->buf_count *
294
                          sizeof(*entry->buflist),
295
                          DRM_MEM_BUFS);
296
 
297
#if __HAVE_DMA_FREELIST
298
                DRM(freelist_destroy)(&entry->freelist);
299
#endif
300
 
301
                entry->buf_count = 0;
302
        }
303
}
304
 
305
#if __REALLY_HAVE_AGP
306
int DRM(addbufs_agp)( struct inode *inode, struct file *filp,
307
                      unsigned int cmd, unsigned long arg )
308
{
309
        drm_file_t *priv = filp->private_data;
310
        drm_device_t *dev = priv->dev;
311
        drm_device_dma_t *dma = dev->dma;
312
        drm_buf_desc_t request;
313
        drm_buf_entry_t *entry;
314
        drm_buf_t *buf;
315
        unsigned long offset;
316
        unsigned long agp_offset;
317
        int count;
318
        int order;
319
        int size;
320
        int alignment;
321
        int page_order;
322
        int total;
323
        int byte_count;
324
        int i;
325
        drm_buf_t **temp_buflist;
326
 
327
        if ( !dma ) return -EINVAL;
328
 
329
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
330
                             sizeof(request) ) )
331
                return -EFAULT;
332
 
333
        count = request.count;
334
        order = DRM(order)( request.size );
335
        size = 1 << order;
336
 
337
        alignment  = (request.flags & _DRM_PAGE_ALIGN)
338
                ? PAGE_ALIGN(size) : size;
339
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
340
        total = PAGE_SIZE << page_order;
341
 
342
        byte_count = 0;
343
        agp_offset = dev->agp->base + request.agp_start;
344
 
345
        DRM_DEBUG( "count:      %d\n",  count );
346
        DRM_DEBUG( "order:      %d\n",  order );
347
        DRM_DEBUG( "size:       %d\n",  size );
348
        DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
349
        DRM_DEBUG( "alignment:  %d\n",  alignment );
350
        DRM_DEBUG( "page_order: %d\n",  page_order );
351
        DRM_DEBUG( "total:      %d\n",  total );
352
 
353
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
354
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
355
 
356
        spin_lock( &dev->count_lock );
357
        if ( dev->buf_use ) {
358
                spin_unlock( &dev->count_lock );
359
                return -EBUSY;
360
        }
361
        atomic_inc( &dev->buf_alloc );
362
        spin_unlock( &dev->count_lock );
363
 
364
        down( &dev->struct_sem );
365
        entry = &dma->bufs[order];
366
        if ( entry->buf_count ) {
367
                up( &dev->struct_sem );
368
                atomic_dec( &dev->buf_alloc );
369
                return -ENOMEM; /* May only call once for each order */
370
        }
371
 
372
        if (count < 0 || count > 4096) {
373
                up( &dev->struct_sem );
374
                atomic_dec( &dev->buf_alloc );
375
                return -EINVAL;
376
        }
377
 
378
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
379
                                    DRM_MEM_BUFS );
380
        if ( !entry->buflist ) {
381
                up( &dev->struct_sem );
382
                atomic_dec( &dev->buf_alloc );
383
                return -ENOMEM;
384
        }
385
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
386
 
387
        entry->buf_size = size;
388
        entry->page_order = page_order;
389
 
390
        offset = 0;
391
 
392
        while ( entry->buf_count < count ) {
393
                buf          = &entry->buflist[entry->buf_count];
394
                buf->idx     = dma->buf_count + entry->buf_count;
395
                buf->total   = alignment;
396
                buf->order   = order;
397
                buf->used    = 0;
398
 
399
                buf->offset  = (dma->byte_count + offset);
400
                buf->bus_address = agp_offset + offset;
401
                buf->address = (void *)(agp_offset + offset);
402
                buf->next    = NULL;
403
                buf->waiting = 0;
404
                buf->pending = 0;
405
                init_waitqueue_head( &buf->dma_wait );
406
                buf->pid     = 0;
407
 
408
                buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
409
                buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
410
                                               DRM_MEM_BUFS );
411
                if(!buf->dev_private) {
412
                        /* Set count correctly so we free the proper amount. */
413
                        entry->buf_count = count;
414
                        DRM(cleanup_buf_error)(entry);
415
                }
416
                memset( buf->dev_private, 0, buf->dev_priv_size );
417
 
418
#if __HAVE_DMA_HISTOGRAM
419
                buf->time_queued = 0;
420
                buf->time_dispatched = 0;
421
                buf->time_completed = 0;
422
                buf->time_freed = 0;
423
#endif
424
                DRM_DEBUG( "buffer %d @ %p\n",
425
                           entry->buf_count, buf->address );
426
 
427
                offset += alignment;
428
                entry->buf_count++;
429
                byte_count += PAGE_SIZE << page_order;
430
        }
431
 
432
        DRM_DEBUG( "byte_count: %d\n", byte_count );
433
 
434
        temp_buflist = DRM(realloc)( dma->buflist,
435
                                     dma->buf_count * sizeof(*dma->buflist),
436
                                     (dma->buf_count + entry->buf_count)
437
                                     * sizeof(*dma->buflist),
438
                                     DRM_MEM_BUFS );
439
        if(!temp_buflist) {
440
                /* Free the entry because it isn't valid */
441
                DRM(cleanup_buf_error)(entry);
442
                up( &dev->struct_sem );
443
                atomic_dec( &dev->buf_alloc );
444
                return -ENOMEM;
445
        }
446
        dma->buflist = temp_buflist;
447
 
448
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
449
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
450
        }
451
 
452
        dma->buf_count += entry->buf_count;
453
        dma->byte_count += byte_count;
454
 
455
        DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
456
        DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
457
 
458
#if __HAVE_DMA_FREELIST
459
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
460
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
461
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
462
        }
463
#endif
464
        up( &dev->struct_sem );
465
 
466
        request.count = entry->buf_count;
467
        request.size = size;
468
 
469
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
470
                return -EFAULT;
471
 
472
        dma->flags = _DRM_DMA_USE_AGP;
473
 
474
        atomic_dec( &dev->buf_alloc );
475
        return 0;
476
}
477
#endif /* __REALLY_HAVE_AGP */
478
 
479
#if __HAVE_PCI_DMA
480
int DRM(addbufs_pci)( struct inode *inode, struct file *filp,
481
                      unsigned int cmd, unsigned long arg )
482
{
483
        drm_file_t *priv = filp->private_data;
484
        drm_device_t *dev = priv->dev;
485
        drm_device_dma_t *dma = dev->dma;
486
        drm_buf_desc_t request;
487
        int count;
488
        int order;
489
        int size;
490
        int total;
491
        int page_order;
492
        drm_buf_entry_t *entry;
493
        unsigned long page;
494
        drm_buf_t *buf;
495
        int alignment;
496
        unsigned long offset;
497
        int i;
498
        int byte_count;
499
        int page_count;
500
        unsigned long *temp_pagelist;
501
        drm_buf_t **temp_buflist;
502
 
503
        if ( !dma ) return -EINVAL;
504
 
505
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
506
                             sizeof(request) ) )
507
                return -EFAULT;
508
 
509
        count = request.count;
510
        order = DRM(order)( request.size );
511
        size = 1 << order;
512
 
513
        DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
514
                   request.count, request.size, size,
515
                   order, dev->queue_count );
516
 
517
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
518
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
519
 
520
        alignment = (request.flags & _DRM_PAGE_ALIGN)
521
                ? PAGE_ALIGN(size) : size;
522
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
523
        total = PAGE_SIZE << page_order;
524
 
525
        spin_lock( &dev->count_lock );
526
        if ( dev->buf_use ) {
527
                spin_unlock( &dev->count_lock );
528
                return -EBUSY;
529
        }
530
        atomic_inc( &dev->buf_alloc );
531
        spin_unlock( &dev->count_lock );
532
 
533
        down( &dev->struct_sem );
534
        entry = &dma->bufs[order];
535
        if ( entry->buf_count ) {
536
                up( &dev->struct_sem );
537
                atomic_dec( &dev->buf_alloc );
538
                return -ENOMEM; /* May only call once for each order */
539
        }
540
 
541
        if (count < 0 || count > 4096) {
542
                up( &dev->struct_sem );
543
                atomic_dec( &dev->buf_alloc );
544
                return -EINVAL;
545
        }
546
 
547
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
548
                                    DRM_MEM_BUFS );
549
        if ( !entry->buflist ) {
550
                up( &dev->struct_sem );
551
                atomic_dec( &dev->buf_alloc );
552
                return -ENOMEM;
553
        }
554
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
555
 
556
        entry->seglist = DRM(alloc)( count * sizeof(*entry->seglist),
557
                                    DRM_MEM_SEGS );
558
        if ( !entry->seglist ) {
559
                DRM(free)( entry->buflist,
560
                          count * sizeof(*entry->buflist),
561
                          DRM_MEM_BUFS );
562
                up( &dev->struct_sem );
563
                atomic_dec( &dev->buf_alloc );
564
                return -ENOMEM;
565
        }
566
        memset( entry->seglist, 0, count * sizeof(*entry->seglist) );
567
 
568
        temp_pagelist = DRM(realloc)( dma->pagelist,
569
                                      dma->page_count * sizeof(*dma->pagelist),
570
                                      (dma->page_count + (count << page_order))
571
                                      * sizeof(*dma->pagelist),
572
                                      DRM_MEM_PAGES );
573
        if(!temp_pagelist) {
574
                DRM(free)( entry->buflist,
575
                           count * sizeof(*entry->buflist),
576
                           DRM_MEM_BUFS );
577
                DRM(free)( entry->seglist,
578
                           count * sizeof(*entry->seglist),
579
                           DRM_MEM_SEGS );
580
                up( &dev->struct_sem );
581
                atomic_dec( &dev->buf_alloc );
582
                return -ENOMEM;
583
        }
584
 
585
        dma->pagelist = temp_pagelist;
586
        DRM_DEBUG( "pagelist: %d entries\n",
587
                   dma->page_count + (count << page_order) );
588
 
589
        entry->buf_size = size;
590
        entry->page_order = page_order;
591
        byte_count = 0;
592
        page_count = 0;
593
 
594
        while ( entry->buf_count < count ) {
595
                page = DRM(alloc_pages)( page_order, DRM_MEM_DMA );
596
                if ( !page ) break;
597
                entry->seglist[entry->seg_count++] = page;
598
                for ( i = 0 ; i < (1 << page_order) ; i++ ) {
599
                        DRM_DEBUG( "page %d @ 0x%08lx\n",
600
                                   dma->page_count + page_count,
601
                                   page + PAGE_SIZE * i );
602
                        dma->pagelist[dma->page_count + page_count++]
603
                                = page + PAGE_SIZE * i;
604
                }
605
                for ( offset = 0 ;
606
                      offset + size <= total && entry->buf_count < count ;
607
                      offset += alignment, ++entry->buf_count ) {
608
                        buf          = &entry->buflist[entry->buf_count];
609
                        buf->idx     = dma->buf_count + entry->buf_count;
610
                        buf->total   = alignment;
611
                        buf->order   = order;
612
                        buf->used    = 0;
613
                        buf->offset  = (dma->byte_count + byte_count + offset);
614
                        buf->address = (void *)(page + offset);
615
                        buf->next    = NULL;
616
                        buf->waiting = 0;
617
                        buf->pending = 0;
618
                        init_waitqueue_head( &buf->dma_wait );
619
                        buf->pid     = 0;
620
#if __HAVE_DMA_HISTOGRAM
621
                        buf->time_queued     = 0;
622
                        buf->time_dispatched = 0;
623
                        buf->time_completed  = 0;
624
                        buf->time_freed      = 0;
625
#endif
626
                        DRM_DEBUG( "buffer %d @ %p\n",
627
                                   entry->buf_count, buf->address );
628
                }
629
                byte_count += PAGE_SIZE << page_order;
630
        }
631
 
632
        temp_buflist = DRM(realloc)( dma->buflist,
633
                                     dma->buf_count * sizeof(*dma->buflist),
634
                                     (dma->buf_count + entry->buf_count)
635
                                     * sizeof(*dma->buflist),
636
                                     DRM_MEM_BUFS );
637
        if(!temp_buflist) {
638
                /* Free the entry because it isn't valid */
639
                DRM(cleanup_buf_error)(entry);
640
                up( &dev->struct_sem );
641
                atomic_dec( &dev->buf_alloc );
642
                return -ENOMEM;
643
        }
644
        dma->buflist = temp_buflist;
645
 
646
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
647
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
648
        }
649
 
650
        dma->buf_count += entry->buf_count;
651
        dma->seg_count += entry->seg_count;
652
        dma->page_count += entry->seg_count << page_order;
653
        dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
654
 
655
#if __HAVE_DMA_FREELIST
656
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
657
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
658
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
659
        }
660
#endif
661
        up( &dev->struct_sem );
662
 
663
        request.count = entry->buf_count;
664
        request.size = size;
665
 
666
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
667
                return -EFAULT;
668
 
669
        atomic_dec( &dev->buf_alloc );
670
        return 0;
671
 
672
}
673
#endif /* __HAVE_PCI_DMA */
674
 
675
#ifdef __HAVE_SG
676
int DRM(addbufs_sg)( struct inode *inode, struct file *filp,
677
                     unsigned int cmd, unsigned long arg )
678
{
679
        drm_file_t *priv = filp->private_data;
680
        drm_device_t *dev = priv->dev;
681
        drm_device_dma_t *dma = dev->dma;
682
        drm_buf_desc_t request;
683
        drm_buf_entry_t *entry;
684
        drm_buf_t *buf;
685
        unsigned long offset;
686
        unsigned long agp_offset;
687
        int count;
688
        int order;
689
        int size;
690
        int alignment;
691
        int page_order;
692
        int total;
693
        int byte_count;
694
        int i;
695
        drm_buf_t **temp_buflist;
696
 
697
        if ( !dma ) return -EINVAL;
698
 
699
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
700
                             sizeof(request) ) )
701
                return -EFAULT;
702
 
703
        count = request.count;
704
        order = DRM(order)( request.size );
705
        size = 1 << order;
706
 
707
        alignment  = (request.flags & _DRM_PAGE_ALIGN)
708
                        ? PAGE_ALIGN(size) : size;
709
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
710
        total = PAGE_SIZE << page_order;
711
 
712
        byte_count = 0;
713
        agp_offset = request.agp_start;
714
 
715
        DRM_DEBUG( "count:      %d\n",  count );
716
        DRM_DEBUG( "order:      %d\n",  order );
717
        DRM_DEBUG( "size:       %d\n",  size );
718
        DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
719
        DRM_DEBUG( "alignment:  %d\n",  alignment );
720
        DRM_DEBUG( "page_order: %d\n",  page_order );
721
        DRM_DEBUG( "total:      %d\n",  total );
722
 
723
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
724
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
725
 
726
        spin_lock( &dev->count_lock );
727
        if ( dev->buf_use ) {
728
                spin_unlock( &dev->count_lock );
729
                return -EBUSY;
730
        }
731
        atomic_inc( &dev->buf_alloc );
732
        spin_unlock( &dev->count_lock );
733
 
734
        down( &dev->struct_sem );
735
        entry = &dma->bufs[order];
736
        if ( entry->buf_count ) {
737
                up( &dev->struct_sem );
738
                atomic_dec( &dev->buf_alloc );
739
                return -ENOMEM; /* May only call once for each order */
740
        }
741
 
742
        if (count < 0 || count > 4096) {
743
                up( &dev->struct_sem );
744
                atomic_dec( &dev->buf_alloc );
745
                return -EINVAL;
746
        }
747
 
748
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
749
                                     DRM_MEM_BUFS );
750
        if ( !entry->buflist ) {
751
                up( &dev->struct_sem );
752
                atomic_dec( &dev->buf_alloc );
753
                return -ENOMEM;
754
        }
755
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
756
 
757
        entry->buf_size = size;
758
        entry->page_order = page_order;
759
 
760
        offset = 0;
761
 
762
        while ( entry->buf_count < count ) {
763
                buf          = &entry->buflist[entry->buf_count];
764
                buf->idx     = dma->buf_count + entry->buf_count;
765
                buf->total   = alignment;
766
                buf->order   = order;
767
                buf->used    = 0;
768
 
769
                buf->offset  = (dma->byte_count + offset);
770
                buf->bus_address = agp_offset + offset;
771
                buf->address = (void *)(agp_offset + offset + dev->sg->handle);
772
                buf->next    = NULL;
773
                buf->waiting = 0;
774
                buf->pending = 0;
775
                init_waitqueue_head( &buf->dma_wait );
776
                buf->pid     = 0;
777
 
778
                buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
779
                buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
780
                                               DRM_MEM_BUFS );
781
                if(!buf->dev_private) {
782
                        /* Set count correctly so we free the proper amount. */
783
                        entry->buf_count = count;
784
                        DRM(cleanup_buf_error)(entry);
785
                        up( &dev->struct_sem );
786
                        atomic_dec( &dev->buf_alloc );
787
                        return -ENOMEM;
788
                }
789
 
790
                memset( buf->dev_private, 0, buf->dev_priv_size );
791
 
792
# if __HAVE_DMA_HISTOGRAM
793
                buf->time_queued = 0;
794
                buf->time_dispatched = 0;
795
                buf->time_completed = 0;
796
                buf->time_freed = 0;
797
# endif
798
                DRM_DEBUG( "buffer %d @ %p\n",
799
                           entry->buf_count, buf->address );
800
 
801
                offset += alignment;
802
                entry->buf_count++;
803
                byte_count += PAGE_SIZE << page_order;
804
        }
805
 
806
        DRM_DEBUG( "byte_count: %d\n", byte_count );
807
 
808
        temp_buflist = DRM(realloc)( dma->buflist,
809
                                     dma->buf_count * sizeof(*dma->buflist),
810
                                     (dma->buf_count + entry->buf_count)
811
                                     * sizeof(*dma->buflist),
812
                                     DRM_MEM_BUFS );
813
        if(!temp_buflist) {
814
                /* Free the entry because it isn't valid */
815
                DRM(cleanup_buf_error)(entry);
816
                up( &dev->struct_sem );
817
                atomic_dec( &dev->buf_alloc );
818
                return -ENOMEM;
819
        }
820
        dma->buflist = temp_buflist;
821
 
822
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
823
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
824
        }
825
 
826
        dma->buf_count += entry->buf_count;
827
        dma->byte_count += byte_count;
828
 
829
        DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
830
        DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
831
 
832
#if __HAVE_DMA_FREELIST
833
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
834
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
835
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
836
        }
837
#endif
838
        up( &dev->struct_sem );
839
 
840
        request.count = entry->buf_count;
841
        request.size = size;
842
 
843
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
844
                return -EFAULT;
845
 
846
        dma->flags = _DRM_DMA_USE_SG;
847
 
848
        atomic_dec( &dev->buf_alloc );
849
        return 0;
850
}
851
#endif /* __HAVE_SG */
852
 
853
int DRM(addbufs)( struct inode *inode, struct file *filp,
854
                  unsigned int cmd, unsigned long arg )
855
{
856
        drm_buf_desc_t request;
857
 
858
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
859
                             sizeof(request) ) )
860
                return -EFAULT;
861
 
862
#if __REALLY_HAVE_AGP
863
        if ( request.flags & _DRM_AGP_BUFFER )
864
                return DRM(addbufs_agp)( inode, filp, cmd, arg );
865
        else
866
#endif
867
#if __HAVE_SG
868
        if ( request.flags & _DRM_SG_BUFFER )
869
                return DRM(addbufs_sg)( inode, filp, cmd, arg );
870
        else
871
#endif
872
#if __HAVE_PCI_DMA
873
                return DRM(addbufs_pci)( inode, filp, cmd, arg );
874
#else
875
                return -EINVAL;
876
#endif
877
}
878
 
879
int DRM(infobufs)( struct inode *inode, struct file *filp,
880
                   unsigned int cmd, unsigned long arg )
881
{
882
        drm_file_t *priv = filp->private_data;
883
        drm_device_t *dev = priv->dev;
884
        drm_device_dma_t *dma = dev->dma;
885
        drm_buf_info_t request;
886
        int i;
887
        int count;
888
 
889
        if ( !dma ) return -EINVAL;
890
 
891
        spin_lock( &dev->count_lock );
892
        if ( atomic_read( &dev->buf_alloc ) ) {
893
                spin_unlock( &dev->count_lock );
894
                return -EBUSY;
895
        }
896
        ++dev->buf_use;         /* Can't allocate more after this call */
897
        spin_unlock( &dev->count_lock );
898
 
899
        if ( copy_from_user( &request,
900
                             (drm_buf_info_t *)arg,
901
                             sizeof(request) ) )
902
                return -EFAULT;
903
 
904
        for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
905
                if ( dma->bufs[i].buf_count ) ++count;
906
        }
907
 
908
        DRM_DEBUG( "count = %d\n", count );
909
 
910
        if ( request.count >= count ) {
911
                for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
912
                        if ( dma->bufs[i].buf_count ) {
913
                                drm_buf_desc_t *to = &request.list[count];
914
                                drm_buf_entry_t *from = &dma->bufs[i];
915
                                drm_freelist_t *list = &dma->bufs[i].freelist;
916
                                if ( copy_to_user( &to->count,
917
                                                   &from->buf_count,
918
                                                   sizeof(from->buf_count) ) ||
919
                                     copy_to_user( &to->size,
920
                                                   &from->buf_size,
921
                                                   sizeof(from->buf_size) ) ||
922
                                     copy_to_user( &to->low_mark,
923
                                                   &list->low_mark,
924
                                                   sizeof(list->low_mark) ) ||
925
                                     copy_to_user( &to->high_mark,
926
                                                   &list->high_mark,
927
                                                   sizeof(list->high_mark) ) )
928
                                        return -EFAULT;
929
 
930
                                DRM_DEBUG( "%d %d %d %d %d\n",
931
                                           i,
932
                                           dma->bufs[i].buf_count,
933
                                           dma->bufs[i].buf_size,
934
                                           dma->bufs[i].freelist.low_mark,
935
                                           dma->bufs[i].freelist.high_mark );
936
                                ++count;
937
                        }
938
                }
939
        }
940
        request.count = count;
941
 
942
        if ( copy_to_user( (drm_buf_info_t *)arg,
943
                           &request,
944
                           sizeof(request) ) )
945
                return -EFAULT;
946
 
947
        return 0;
948
}
949
 
950
int DRM(markbufs)( struct inode *inode, struct file *filp,
951
                   unsigned int cmd, unsigned long arg )
952
{
953
        drm_file_t *priv = filp->private_data;
954
        drm_device_t *dev = priv->dev;
955
        drm_device_dma_t *dma = dev->dma;
956
        drm_buf_desc_t request;
957
        int order;
958
        drm_buf_entry_t *entry;
959
 
960
        if ( !dma ) return -EINVAL;
961
 
962
        if ( copy_from_user( &request,
963
                             (drm_buf_desc_t *)arg,
964
                             sizeof(request) ) )
965
                return -EFAULT;
966
 
967
        DRM_DEBUG( "%d, %d, %d\n",
968
                   request.size, request.low_mark, request.high_mark );
969
        order = DRM(order)( request.size );
970
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
971
        entry = &dma->bufs[order];
972
 
973
        if ( request.low_mark < 0 || request.low_mark > entry->buf_count )
974
                return -EINVAL;
975
        if ( request.high_mark < 0 || request.high_mark > entry->buf_count )
976
                return -EINVAL;
977
 
978
        entry->freelist.low_mark  = request.low_mark;
979
        entry->freelist.high_mark = request.high_mark;
980
 
981
        return 0;
982
}
983
 
984
int DRM(freebufs)( struct inode *inode, struct file *filp,
985
                   unsigned int cmd, unsigned long arg )
986
{
987
        drm_file_t *priv = filp->private_data;
988
        drm_device_t *dev = priv->dev;
989
        drm_device_dma_t *dma = dev->dma;
990
        drm_buf_free_t request;
991
        int i;
992
        int idx;
993
        drm_buf_t *buf;
994
 
995
        if ( !dma ) return -EINVAL;
996
 
997
        if ( copy_from_user( &request,
998
                             (drm_buf_free_t *)arg,
999
                             sizeof(request) ) )
1000
                return -EFAULT;
1001
 
1002
        DRM_DEBUG( "%d\n", request.count );
1003
        for ( i = 0 ; i < request.count ; i++ ) {
1004
                if ( copy_from_user( &idx,
1005
                                     &request.list[i],
1006
                                     sizeof(idx) ) )
1007
                        return -EFAULT;
1008
                if ( idx < 0 || idx >= dma->buf_count ) {
1009
                        DRM_ERROR( "Index %d (of %d max)\n",
1010
                                   idx, dma->buf_count - 1 );
1011
                        return -EINVAL;
1012
                }
1013
                buf = dma->buflist[idx];
1014
                if ( buf->pid != current->pid ) {
1015
                        DRM_ERROR( "Process %d freeing buffer owned by %d\n",
1016
                                   current->pid, buf->pid );
1017
                        return -EINVAL;
1018
                }
1019
                DRM(free_buffer)( dev, buf );
1020
        }
1021
 
1022
        return 0;
1023
}
1024
 
1025
int DRM(mapbufs)( struct inode *inode, struct file *filp,
1026
                  unsigned int cmd, unsigned long arg )
1027
{
1028
        drm_file_t *priv = filp->private_data;
1029
        drm_device_t *dev = priv->dev;
1030
        drm_device_dma_t *dma = dev->dma;
1031
        int retcode = 0;
1032
        const int zero = 0;
1033
        unsigned long virtual;
1034
        unsigned long address;
1035
        drm_buf_map_t request;
1036
        int i;
1037
 
1038
        if ( !dma ) return -EINVAL;
1039
 
1040
        spin_lock( &dev->count_lock );
1041
        if ( atomic_read( &dev->buf_alloc ) ) {
1042
                spin_unlock( &dev->count_lock );
1043
                return -EBUSY;
1044
        }
1045
        dev->buf_use++;         /* Can't allocate more after this call */
1046
        spin_unlock( &dev->count_lock );
1047
 
1048
        if ( copy_from_user( &request, (drm_buf_map_t *)arg,
1049
                             sizeof(request) ) )
1050
                return -EFAULT;
1051
 
1052
        if ( request.count >= dma->buf_count ) {
1053
                if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) ||
1054
                     (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) {
1055
                        drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );
1056
 
1057
                        if ( !map ) {
1058
                                retcode = -EINVAL;
1059
                                goto done;
1060
                        }
1061
 
1062
                        down_write( &current->mm->mmap_sem );
1063
                        virtual = do_mmap( filp, 0, map->size,
1064
                                           PROT_READ | PROT_WRITE,
1065
                                           MAP_SHARED,
1066
                                           (unsigned long)map->offset );
1067
                        up_write( &current->mm->mmap_sem );
1068
                } else {
1069
                        down_write( &current->mm->mmap_sem );
1070
                        virtual = do_mmap( filp, 0, dma->byte_count,
1071
                                           PROT_READ | PROT_WRITE,
1072
                                           MAP_SHARED, 0 );
1073
                        up_write( &current->mm->mmap_sem );
1074
                }
1075
                if ( virtual > -1024UL ) {
1076
                        /* Real error */
1077
                        retcode = (signed long)virtual;
1078
                        goto done;
1079
                }
1080
                request.virtual = (void *)virtual;
1081
 
1082
                for ( i = 0 ; i < dma->buf_count ; i++ ) {
1083
                        if ( copy_to_user( &request.list[i].idx,
1084
                                           &dma->buflist[i]->idx,
1085
                                           sizeof(request.list[0].idx) ) ) {
1086
                                retcode = -EFAULT;
1087
                                goto done;
1088
                        }
1089
                        if ( copy_to_user( &request.list[i].total,
1090
                                           &dma->buflist[i]->total,
1091
                                           sizeof(request.list[0].total) ) ) {
1092
                                retcode = -EFAULT;
1093
                                goto done;
1094
                        }
1095
                        if ( copy_to_user( &request.list[i].used,
1096
                                           &zero,
1097
                                           sizeof(zero) ) ) {
1098
                                retcode = -EFAULT;
1099
                                goto done;
1100
                        }
1101
                        address = virtual + dma->buflist[i]->offset; /* *** */
1102
                        if ( copy_to_user( &request.list[i].address,
1103
                                           &address,
1104
                                           sizeof(address) ) ) {
1105
                                retcode = -EFAULT;
1106
                                goto done;
1107
                        }
1108
                }
1109
        }
1110
 done:
1111
        request.count = dma->buf_count;
1112
        DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode );
1113
 
1114
        if ( copy_to_user( (drm_buf_map_t *)arg, &request, sizeof(request) ) )
1115
                return -EFAULT;
1116
 
1117
        return retcode;
1118
}
1119
 
1120
#endif /* __HAVE_DMA */

powered by: WebSVN 2.1.0

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