ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / char / drm / drm_proc.h
1 /**
2  * \file drm_proc.h 
3  * /proc support for DRM
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  *
8  * \par Acknowledgements:
9  *    Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix
10  *    the problem with the proc files not outputting all their information.
11  */
12
13 /*
14  * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com
15  *
16  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
17  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
18  * All Rights Reserved.
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining a
21  * copy of this software and associated documentation files (the "Software"),
22  * to deal in the Software without restriction, including without limitation
23  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24  * and/or sell copies of the Software, and to permit persons to whom the
25  * Software is furnished to do so, subject to the following conditions:
26  *
27  * The above copyright notice and this permission notice (including the next
28  * paragraph) shall be included in all copies or substantial portions of the
29  * Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
34  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
35  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
36  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
37  * OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include "drmP.h"
41
42 static int         DRM(name_info)(char *buf, char **start, off_t offset,
43                                   int request, int *eof, void *data);
44 static int         DRM(vm_info)(char *buf, char **start, off_t offset,
45                                 int request, int *eof, void *data);
46 static int         DRM(clients_info)(char *buf, char **start, off_t offset,
47                                      int request, int *eof, void *data);
48 static int         DRM(queues_info)(char *buf, char **start, off_t offset,
49                                     int request, int *eof, void *data);
50 static int         DRM(bufs_info)(char *buf, char **start, off_t offset,
51                                   int request, int *eof, void *data);
52 #if DRM_DEBUG_CODE
53 static int         DRM(vma_info)(char *buf, char **start, off_t offset,
54                                  int request, int *eof, void *data);
55 #endif
56
57 /**
58  * Proc file list.
59  */
60 struct drm_proc_list {
61         const char *name;       /**< file name */
62         int        (*f)(char *, char **, off_t, int, int *, void *);    /**< proc callback*/
63 } DRM(proc_list)[] = {
64         { "name",    DRM(name_info)    },
65         { "mem",     DRM(mem_info)     },
66         { "vm",      DRM(vm_info)      },
67         { "clients", DRM(clients_info) },
68         { "queues",  DRM(queues_info)  },
69         { "bufs",    DRM(bufs_info)    },
70 #if DRM_DEBUG_CODE
71         { "vma",     DRM(vma_info)     },
72 #endif
73 };
74 #define DRM_PROC_ENTRIES (sizeof(DRM(proc_list))/sizeof(DRM(proc_list)[0]))
75
76 /**
77  * Initialize the DRI proc filesystem for a device.
78  *
79  * \param dev DRM device.
80  * \param minor device minor number.
81  * \param root DRI proc dir entry.
82  * \param dev_root resulting DRI device proc dir entry.
83  * \return root entry pointer on success, or NULL on failure.
84  * 
85  * Create the DRI proc root entry "/proc/dri", the device proc root entry
86  * "/proc/dri/%minor%/", and each entry in proc_list as
87  * "/proc/dri/%minor%/%name%".
88  */
89 struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev, int minor,
90                                       struct proc_dir_entry *root,
91                                       struct proc_dir_entry **dev_root)
92 {
93         struct proc_dir_entry *ent;
94         int                   i, j;
95         char                  name[64];
96
97         if (!minor) root = create_proc_entry("dri", S_IFDIR, NULL);
98         if (!root) {
99                 DRM_ERROR("Cannot create /proc/dri\n");
100                 return NULL;
101         }
102
103         sprintf(name, "%d", minor);
104         *dev_root = create_proc_entry(name, S_IFDIR, root);
105         if (!*dev_root) {
106                 DRM_ERROR("Cannot create /proc/dri/%s\n", name);
107                 return NULL;
108         }
109
110         for (i = 0; i < DRM_PROC_ENTRIES; i++) {
111                 ent = create_proc_entry(DRM(proc_list)[i].name,
112                                         S_IFREG|S_IRUGO, *dev_root);
113                 if (!ent) {
114                         DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
115                                   name, DRM(proc_list)[i].name);
116                         for (j = 0; j < i; j++)
117                                 remove_proc_entry(DRM(proc_list)[i].name,
118                                                   *dev_root);
119                         remove_proc_entry(name, root);
120                         if (!minor) remove_proc_entry("dri", NULL);
121                         return NULL;
122                 }
123                 ent->read_proc = DRM(proc_list)[i].f;
124                 ent->data      = dev;
125         }
126
127         return root;
128 }
129
130
131 /**
132  * Cleanup the proc filesystem resources.
133  *
134  * \param minor device minor number.
135  * \param root DRI proc dir entry.
136  * \param dev_root DRI device proc dir entry.
137  * \return always zero.
138  *
139  * Remove all proc entries created by proc_init().
140  */
141 int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root,
142                       struct proc_dir_entry *dev_root)
143 {
144         int  i;
145         char name[64];
146
147         if (!root || !dev_root) return 0;
148
149         for (i = 0; i < DRM_PROC_ENTRIES; i++)
150                 remove_proc_entry(DRM(proc_list)[i].name, dev_root);
151         sprintf(name, "%d", minor);
152         remove_proc_entry(name, root);
153         if (!minor) remove_proc_entry("dri", NULL);
154
155         return 0;
156 }
157
158 /**
159  * Called when "/proc/dri/.../name" is read.
160  * 
161  * \param buf output buffer.
162  * \param start start of output data.
163  * \param offset requested start offset.
164  * \param request requested number of bytes.
165  * \param eof whether there is no more data to return.
166  * \param data private data.
167  * \return number of written bytes.
168  * 
169  * Prints the device name together with the bus id if available.
170  */
171 static int DRM(name_info)(char *buf, char **start, off_t offset, int request,
172                           int *eof, void *data)
173 {
174         drm_device_t *dev = (drm_device_t *)data;
175         int          len  = 0;
176
177         if (offset > DRM_PROC_LIMIT) {
178                 *eof = 1;
179                 return 0;
180         }
181
182         *start = &buf[offset];
183         *eof   = 0;
184
185         if (dev->unique) {
186                 DRM_PROC_PRINT("%s 0x%lx %s\n",
187                                dev->name, (long)old_encode_dev(dev->device), dev->unique);
188         } else {
189                 DRM_PROC_PRINT("%s 0x%lx\n", dev->name, (long)old_encode_dev(dev->device));
190         }
191
192         if (len > request + offset) return request;
193         *eof = 1;
194         return len - offset;
195 }
196
197 /**
198  * Called when "/proc/dri/.../vm" is read.
199  * 
200  * \param buf output buffer.
201  * \param start start of output data.
202  * \param offset requested start offset.
203  * \param request requested number of bytes.
204  * \param eof whether there is no more data to return.
205  * \param data private data.
206  * \return number of written bytes.
207  * 
208  * Prints information about all mappings in drm_device::maplist.
209  */
210 static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request,
211                          int *eof, void *data)
212 {
213         drm_device_t *dev = (drm_device_t *)data;
214         int          len  = 0;
215         drm_map_t    *map;
216         drm_map_list_t *r_list;
217         struct list_head *list;
218
219                                 /* Hardcoded from _DRM_FRAME_BUFFER,
220                                    _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
221                                    _DRM_SCATTER_GATHER. */
222         const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
223         const char   *type;
224         int          i;
225
226         if (offset > DRM_PROC_LIMIT) {
227                 *eof = 1;
228                 return 0;
229         }
230
231         *start = &buf[offset];
232         *eof   = 0;
233
234         DRM_PROC_PRINT("slot     offset       size type flags    "
235                        "address mtrr\n\n");
236         i = 0;
237         if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) {
238                 r_list = list_entry(list, drm_map_list_t, head);
239                 map = r_list->map;
240                 if(!map) continue;
241                 if (map->type < 0 || map->type > 4) type = "??";
242                 else                                type = types[map->type];
243                 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
244                                i,
245                                map->offset,
246                                map->size,
247                                type,
248                                map->flags,
249                                (unsigned long)map->handle);
250                 if (map->mtrr < 0) {
251                         DRM_PROC_PRINT("none\n");
252                 } else {
253                         DRM_PROC_PRINT("%4d\n", map->mtrr);
254                 }
255                 i++;
256         }
257
258         if (len > request + offset) return request;
259         *eof = 1;
260         return len - offset;
261 }
262
263 /**
264  * Simply calls _vm_info() while holding the drm_device::struct_sem lock.
265  */
266 static int DRM(vm_info)(char *buf, char **start, off_t offset, int request,
267                         int *eof, void *data)
268 {
269         drm_device_t *dev = (drm_device_t *)data;
270         int          ret;
271
272         down(&dev->struct_sem);
273         ret = DRM(_vm_info)(buf, start, offset, request, eof, data);
274         up(&dev->struct_sem);
275         return ret;
276 }
277
278 /**
279  * Called when "/proc/dri/.../queues" is read.
280  * 
281  * \param buf output buffer.
282  * \param start start of output data.
283  * \param offset requested start offset.
284  * \param request requested number of bytes.
285  * \param eof whether there is no more data to return.
286  * \param data private data.
287  * \return number of written bytes.
288  */
289 static int DRM(_queues_info)(char *buf, char **start, off_t offset,
290                              int request, int *eof, void *data)
291 {
292         drm_device_t *dev = (drm_device_t *)data;
293         int          len  = 0;
294         int          i;
295         drm_queue_t  *q;
296
297         if (offset > DRM_PROC_LIMIT) {
298                 *eof = 1;
299                 return 0;
300         }
301
302         *start = &buf[offset];
303         *eof   = 0;
304
305         DRM_PROC_PRINT("  ctx/flags   use   fin"
306                        "   blk/rw/rwf  wait    flushed     queued"
307                        "      locks\n\n");
308         for (i = 0; i < dev->queue_count; i++) {
309                 q = dev->queuelist[i];
310                 atomic_inc(&q->use_count);
311                 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
312                                    "%5d/0x%03x %5d %5d"
313                                    " %5d/%c%c/%c%c%c %5Zd\n",
314                                    i,
315                                    q->flags,
316                                    atomic_read(&q->use_count),
317                                    atomic_read(&q->finalization),
318                                    atomic_read(&q->block_count),
319                                    atomic_read(&q->block_read) ? 'r' : '-',
320                                    atomic_read(&q->block_write) ? 'w' : '-',
321                                    waitqueue_active(&q->read_queue) ? 'r':'-',
322                                    waitqueue_active(&q->write_queue) ? 'w':'-',
323                                    waitqueue_active(&q->flush_queue) ? 'f':'-',
324                                    DRM_BUFCOUNT(&q->waitlist));
325                 atomic_dec(&q->use_count);
326         }
327
328         if (len > request + offset) return request;
329         *eof = 1;
330         return len - offset;
331 }
332
333 /**
334  * Simply calls _queues_info() while holding the drm_device::struct_sem lock.
335  */
336 static int DRM(queues_info)(char *buf, char **start, off_t offset, int request,
337                             int *eof, void *data)
338 {
339         drm_device_t *dev = (drm_device_t *)data;
340         int          ret;
341
342         down(&dev->struct_sem);
343         ret = DRM(_queues_info)(buf, start, offset, request, eof, data);
344         up(&dev->struct_sem);
345         return ret;
346 }
347
348 /**
349  * Called when "/proc/dri/.../bufs" is read.
350  * 
351  * \param buf output buffer.
352  * \param start start of output data.
353  * \param offset requested start offset.
354  * \param request requested number of bytes.
355  * \param eof whether there is no more data to return.
356  * \param data private data.
357  * \return number of written bytes.
358  */
359 static int DRM(_bufs_info)(char *buf, char **start, off_t offset, int request,
360                            int *eof, void *data)
361 {
362         drm_device_t     *dev = (drm_device_t *)data;
363         int              len  = 0;
364         drm_device_dma_t *dma = dev->dma;
365         int              i;
366
367         if (!dma || offset > DRM_PROC_LIMIT) {
368                 *eof = 1;
369                 return 0;
370         }
371
372         *start = &buf[offset];
373         *eof   = 0;
374
375         DRM_PROC_PRINT(" o     size count  free  segs pages    kB\n\n");
376         for (i = 0; i <= DRM_MAX_ORDER; i++) {
377                 if (dma->bufs[i].buf_count)
378                         DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
379                                        i,
380                                        dma->bufs[i].buf_size,
381                                        dma->bufs[i].buf_count,
382                                        atomic_read(&dma->bufs[i]
383                                                    .freelist.count),
384                                        dma->bufs[i].seg_count,
385                                        dma->bufs[i].seg_count
386                                        *(1 << dma->bufs[i].page_order),
387                                        (dma->bufs[i].seg_count
388                                         * (1 << dma->bufs[i].page_order))
389                                        * PAGE_SIZE / 1024);
390         }
391         DRM_PROC_PRINT("\n");
392         for (i = 0; i < dma->buf_count; i++) {
393                 if (i && !(i%32)) DRM_PROC_PRINT("\n");
394                 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
395         }
396         DRM_PROC_PRINT("\n");
397
398         if (len > request + offset) return request;
399         *eof = 1;
400         return len - offset;
401 }
402
403 /**
404  * Simply calls _bufs_info() while holding the drm_device::struct_sem lock.
405  */
406 static int DRM(bufs_info)(char *buf, char **start, off_t offset, int request,
407                           int *eof, void *data)
408 {
409         drm_device_t *dev = (drm_device_t *)data;
410         int          ret;
411
412         down(&dev->struct_sem);
413         ret = DRM(_bufs_info)(buf, start, offset, request, eof, data);
414         up(&dev->struct_sem);
415         return ret;
416 }
417
418 /**
419  * Called when "/proc/dri/.../clients" is read.
420  * 
421  * \param buf output buffer.
422  * \param start start of output data.
423  * \param offset requested start offset.
424  * \param request requested number of bytes.
425  * \param eof whether there is no more data to return.
426  * \param data private data.
427  * \return number of written bytes.
428  */
429 static int DRM(_clients_info)(char *buf, char **start, off_t offset,
430                               int request, int *eof, void *data)
431 {
432         drm_device_t *dev = (drm_device_t *)data;
433         int          len  = 0;
434         drm_file_t   *priv;
435
436         if (offset > DRM_PROC_LIMIT) {
437                 *eof = 1;
438                 return 0;
439         }
440
441         *start = &buf[offset];
442         *eof   = 0;
443
444         DRM_PROC_PRINT("a dev   pid    uid      magic     ioctls\n\n");
445         for (priv = dev->file_first; priv; priv = priv->next) {
446                 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
447                                priv->authenticated ? 'y' : 'n',
448                                priv->minor,
449                                priv->pid,
450                                priv->uid,
451                                priv->magic,
452                                priv->ioctl_count);
453         }
454
455         if (len > request + offset) return request;
456         *eof = 1;
457         return len - offset;
458 }
459
460 /**
461  * Simply calls _clients_info() while holding the drm_device::struct_sem lock.
462  */
463 static int DRM(clients_info)(char *buf, char **start, off_t offset,
464                              int request, int *eof, void *data)
465 {
466         drm_device_t *dev = (drm_device_t *)data;
467         int          ret;
468
469         down(&dev->struct_sem);
470         ret = DRM(_clients_info)(buf, start, offset, request, eof, data);
471         up(&dev->struct_sem);
472         return ret;
473 }
474
475 #if DRM_DEBUG_CODE
476
477 static int DRM(_vma_info)(char *buf, char **start, off_t offset, int request,
478                           int *eof, void *data)
479 {
480         drm_device_t          *dev = (drm_device_t *)data;
481         int                   len  = 0;
482         drm_vma_entry_t       *pt;
483         struct vm_area_struct *vma;
484 #if defined(__i386__)
485         unsigned int          pgprot;
486 #endif
487
488         if (offset > DRM_PROC_LIMIT) {
489                 *eof = 1;
490                 return 0;
491         }
492
493         *start = &buf[offset];
494         *eof   = 0;
495
496         DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
497                        atomic_read(&dev->vma_count),
498                        high_memory, virt_to_phys(high_memory));
499         for (pt = dev->vmalist; pt; pt = pt->next) {
500                 if (!(vma = pt->vma)) continue;
501                 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
502                                pt->pid,
503                                vma->vm_start,
504                                vma->vm_end,
505                                vma->vm_flags & VM_READ     ? 'r' : '-',
506                                vma->vm_flags & VM_WRITE    ? 'w' : '-',
507                                vma->vm_flags & VM_EXEC     ? 'x' : '-',
508                                vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
509                                vma->vm_flags & VM_LOCKED   ? 'l' : '-',
510                                vma->vm_flags & VM_IO       ? 'i' : '-',
511                                VM_OFFSET(vma));
512
513 #if defined(__i386__)
514                 pgprot = pgprot_val(vma->vm_page_prot);
515                 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
516                                pgprot & _PAGE_PRESENT  ? 'p' : '-',
517                                pgprot & _PAGE_RW       ? 'w' : 'r',
518                                pgprot & _PAGE_USER     ? 'u' : 's',
519                                pgprot & _PAGE_PWT      ? 't' : 'b',
520                                pgprot & _PAGE_PCD      ? 'u' : 'c',
521                                pgprot & _PAGE_ACCESSED ? 'a' : '-',
522                                pgprot & _PAGE_DIRTY    ? 'd' : '-',
523                                pgprot & _PAGE_PSE      ? 'm' : 'k',
524                                pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
525 #endif
526                 DRM_PROC_PRINT("\n");
527         }
528
529         if (len > request + offset) return request;
530         *eof = 1;
531         return len - offset;
532 }
533
534 static int DRM(vma_info)(char *buf, char **start, off_t offset, int request,
535                          int *eof, void *data)
536 {
537         drm_device_t *dev = (drm_device_t *)data;
538         int          ret;
539
540         down(&dev->struct_sem);
541         ret = DRM(_vma_info)(buf, start, offset, request, eof, data);
542         up(&dev->struct_sem);
543         return ret;
544 }
545 #endif
546
547