vserver 2.0 rc7
[linux-2.6.git] / drivers / char / drm / drm_proc.c
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 int 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         sprintf(name, "%d", minor);
98         *dev_root = create_proc_entry(name, S_IFDIR, root);
99         if (!*dev_root) {
100                 DRM_ERROR("Cannot create /proc/dri/%s\n", name);
101                 return -1;
102         }
103
104         for (i = 0; i < DRM_PROC_ENTRIES; i++) {
105                 ent = create_proc_entry(drm_proc_list[i].name,
106                                         S_IFREG|S_IRUGO, *dev_root);
107                 if (!ent) {
108                         DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
109                                   name, drm_proc_list[i].name);
110                         for (j = 0; j < i; j++)
111                                 remove_proc_entry(drm_proc_list[i].name,
112                                                   *dev_root);
113                         remove_proc_entry(name, root);
114                         return -1;
115                 }
116                 ent->read_proc = drm_proc_list[i].f;
117                 ent->data      = dev;
118         }
119
120         return 0;
121 }
122
123
124 /**
125  * Cleanup the proc filesystem resources.
126  *
127  * \param minor device minor number.
128  * \param root DRI proc dir entry.
129  * \param dev_root DRI device proc dir entry.
130  * \return always zero.
131  *
132  * Remove all proc entries created by proc_init().
133  */
134 int drm_proc_cleanup(int minor, struct proc_dir_entry *root,
135                       struct proc_dir_entry *dev_root)
136 {
137         int  i;
138         char name[64];
139
140         if (!root || !dev_root) return 0;
141
142         for (i = 0; i < DRM_PROC_ENTRIES; i++)
143                 remove_proc_entry(drm_proc_list[i].name, dev_root);
144         sprintf(name, "%d", minor);
145         remove_proc_entry(name, root);
146
147         return 0;
148 }
149
150 /**
151  * Called when "/proc/dri/.../name" is read.
152  * 
153  * \param buf output buffer.
154  * \param start start of output data.
155  * \param offset requested start offset.
156  * \param request requested number of bytes.
157  * \param eof whether there is no more data to return.
158  * \param data private data.
159  * \return number of written bytes.
160  * 
161  * Prints the device name together with the bus id if available.
162  */
163 static int drm_name_info(char *buf, char **start, off_t offset, int request,
164                           int *eof, void *data)
165 {
166         drm_device_t *dev = (drm_device_t *)data;
167         int          len  = 0;
168
169         if (offset > DRM_PROC_LIMIT) {
170                 *eof = 1;
171                 return 0;
172         }
173
174         *start = &buf[offset];
175         *eof   = 0;
176
177         if (dev->unique) {
178                 DRM_PROC_PRINT("%s %s %s\n",
179                                dev->driver->pci_driver.name, pci_name(dev->pdev), dev->unique);
180         } else {
181                 DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, pci_name(dev->pdev));
182         }
183
184         if (len > request + offset) return request;
185         *eof = 1;
186         return len - offset;
187 }
188
189 /**
190  * Called when "/proc/dri/.../vm" is read.
191  * 
192  * \param buf output buffer.
193  * \param start start of output data.
194  * \param offset requested start offset.
195  * \param request requested number of bytes.
196  * \param eof whether there is no more data to return.
197  * \param data private data.
198  * \return number of written bytes.
199  * 
200  * Prints information about all mappings in drm_device::maplist.
201  */
202 static int drm__vm_info(char *buf, char **start, off_t offset, int request,
203                          int *eof, void *data)
204 {
205         drm_device_t *dev = (drm_device_t *)data;
206         int          len  = 0;
207         drm_map_t    *map;
208         drm_map_list_t *r_list;
209         struct list_head *list;
210
211                                 /* Hardcoded from _DRM_FRAME_BUFFER,
212                                    _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
213                                    _DRM_SCATTER_GATHER. */
214         const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
215         const char   *type;
216         int          i;
217
218         if (offset > DRM_PROC_LIMIT) {
219                 *eof = 1;
220                 return 0;
221         }
222
223         *start = &buf[offset];
224         *eof   = 0;
225
226         DRM_PROC_PRINT("slot     offset       size type flags    "
227                        "address mtrr\n\n");
228         i = 0;
229         if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) {
230                 r_list = list_entry(list, drm_map_list_t, head);
231                 map = r_list->map;
232                 if(!map) continue;
233                 if (map->type < 0 || map->type > 4) type = "??";
234                 else                                type = types[map->type];
235                 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
236                                i,
237                                map->offset,
238                                map->size,
239                                type,
240                                map->flags,
241                                (unsigned long)map->handle);
242                 if (map->mtrr < 0) {
243                         DRM_PROC_PRINT("none\n");
244                 } else {
245                         DRM_PROC_PRINT("%4d\n", map->mtrr);
246                 }
247                 i++;
248         }
249
250         if (len > request + offset) return request;
251         *eof = 1;
252         return len - offset;
253 }
254
255 /**
256  * Simply calls _vm_info() while holding the drm_device::struct_sem lock.
257  */
258 static int drm_vm_info(char *buf, char **start, off_t offset, int request,
259                         int *eof, void *data)
260 {
261         drm_device_t *dev = (drm_device_t *)data;
262         int          ret;
263
264         down(&dev->struct_sem);
265         ret = drm__vm_info(buf, start, offset, request, eof, data);
266         up(&dev->struct_sem);
267         return ret;
268 }
269
270 /**
271  * Called when "/proc/dri/.../queues" is read.
272  * 
273  * \param buf output buffer.
274  * \param start start of output data.
275  * \param offset requested start offset.
276  * \param request requested number of bytes.
277  * \param eof whether there is no more data to return.
278  * \param data private data.
279  * \return number of written bytes.
280  */
281 static int drm__queues_info(char *buf, char **start, off_t offset,
282                              int request, int *eof, void *data)
283 {
284         drm_device_t *dev = (drm_device_t *)data;
285         int          len  = 0;
286         int          i;
287         drm_queue_t  *q;
288
289         if (offset > DRM_PROC_LIMIT) {
290                 *eof = 1;
291                 return 0;
292         }
293
294         *start = &buf[offset];
295         *eof   = 0;
296
297         DRM_PROC_PRINT("  ctx/flags   use   fin"
298                        "   blk/rw/rwf  wait    flushed     queued"
299                        "      locks\n\n");
300         for (i = 0; i < dev->queue_count; i++) {
301                 q = dev->queuelist[i];
302                 atomic_inc(&q->use_count);
303                 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
304                                    "%5d/0x%03x %5d %5d"
305                                    " %5d/%c%c/%c%c%c %5Zd\n",
306                                    i,
307                                    q->flags,
308                                    atomic_read(&q->use_count),
309                                    atomic_read(&q->finalization),
310                                    atomic_read(&q->block_count),
311                                    atomic_read(&q->block_read) ? 'r' : '-',
312                                    atomic_read(&q->block_write) ? 'w' : '-',
313                                    waitqueue_active(&q->read_queue) ? 'r':'-',
314                                    waitqueue_active(&q->write_queue) ? 'w':'-',
315                                    waitqueue_active(&q->flush_queue) ? 'f':'-',
316                                    DRM_BUFCOUNT(&q->waitlist));
317                 atomic_dec(&q->use_count);
318         }
319
320         if (len > request + offset) return request;
321         *eof = 1;
322         return len - offset;
323 }
324
325 /**
326  * Simply calls _queues_info() while holding the drm_device::struct_sem lock.
327  */
328 static int drm_queues_info(char *buf, char **start, off_t offset, int request,
329                             int *eof, void *data)
330 {
331         drm_device_t *dev = (drm_device_t *)data;
332         int          ret;
333
334         down(&dev->struct_sem);
335         ret = drm__queues_info(buf, start, offset, request, eof, data);
336         up(&dev->struct_sem);
337         return ret;
338 }
339
340 /**
341  * Called when "/proc/dri/.../bufs" is read.
342  * 
343  * \param buf output buffer.
344  * \param start start of output data.
345  * \param offset requested start offset.
346  * \param request requested number of bytes.
347  * \param eof whether there is no more data to return.
348  * \param data private data.
349  * \return number of written bytes.
350  */
351 static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
352                            int *eof, void *data)
353 {
354         drm_device_t     *dev = (drm_device_t *)data;
355         int              len  = 0;
356         drm_device_dma_t *dma = dev->dma;
357         int              i;
358
359         if (!dma || offset > DRM_PROC_LIMIT) {
360                 *eof = 1;
361                 return 0;
362         }
363
364         *start = &buf[offset];
365         *eof   = 0;
366
367         DRM_PROC_PRINT(" o     size count  free  segs pages    kB\n\n");
368         for (i = 0; i <= DRM_MAX_ORDER; i++) {
369                 if (dma->bufs[i].buf_count)
370                         DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
371                                        i,
372                                        dma->bufs[i].buf_size,
373                                        dma->bufs[i].buf_count,
374                                        atomic_read(&dma->bufs[i]
375                                                    .freelist.count),
376                                        dma->bufs[i].seg_count,
377                                        dma->bufs[i].seg_count
378                                        *(1 << dma->bufs[i].page_order),
379                                        (dma->bufs[i].seg_count
380                                         * (1 << dma->bufs[i].page_order))
381                                        * PAGE_SIZE / 1024);
382         }
383         DRM_PROC_PRINT("\n");
384         for (i = 0; i < dma->buf_count; i++) {
385                 if (i && !(i%32)) DRM_PROC_PRINT("\n");
386                 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
387         }
388         DRM_PROC_PRINT("\n");
389
390         if (len > request + offset) return request;
391         *eof = 1;
392         return len - offset;
393 }
394
395 /**
396  * Simply calls _bufs_info() while holding the drm_device::struct_sem lock.
397  */
398 static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
399                           int *eof, void *data)
400 {
401         drm_device_t *dev = (drm_device_t *)data;
402         int          ret;
403
404         down(&dev->struct_sem);
405         ret = drm__bufs_info(buf, start, offset, request, eof, data);
406         up(&dev->struct_sem);
407         return ret;
408 }
409
410 /**
411  * Called when "/proc/dri/.../clients" is read.
412  * 
413  * \param buf output buffer.
414  * \param start start of output data.
415  * \param offset requested start offset.
416  * \param request requested number of bytes.
417  * \param eof whether there is no more data to return.
418  * \param data private data.
419  * \return number of written bytes.
420  */
421 static int drm__clients_info(char *buf, char **start, off_t offset,
422                               int request, int *eof, void *data)
423 {
424         drm_device_t *dev = (drm_device_t *)data;
425         int          len  = 0;
426         drm_file_t   *priv;
427
428         if (offset > DRM_PROC_LIMIT) {
429                 *eof = 1;
430                 return 0;
431         }
432
433         *start = &buf[offset];
434         *eof   = 0;
435
436         DRM_PROC_PRINT("a dev   pid    uid      magic     ioctls\n\n");
437         for (priv = dev->file_first; priv; priv = priv->next) {
438                 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
439                                priv->authenticated ? 'y' : 'n',
440                                priv->minor,
441                                priv->pid,
442                                priv->uid,
443                                priv->magic,
444                                priv->ioctl_count);
445         }
446
447         if (len > request + offset) return request;
448         *eof = 1;
449         return len - offset;
450 }
451
452 /**
453  * Simply calls _clients_info() while holding the drm_device::struct_sem lock.
454  */
455 static int drm_clients_info(char *buf, char **start, off_t offset,
456                              int request, int *eof, void *data)
457 {
458         drm_device_t *dev = (drm_device_t *)data;
459         int          ret;
460
461         down(&dev->struct_sem);
462         ret = drm__clients_info(buf, start, offset, request, eof, data);
463         up(&dev->struct_sem);
464         return ret;
465 }
466
467 #if DRM_DEBUG_CODE
468
469 static int drm__vma_info(char *buf, char **start, off_t offset, int request,
470                           int *eof, void *data)
471 {
472         drm_device_t          *dev = (drm_device_t *)data;
473         int                   len  = 0;
474         drm_vma_entry_t       *pt;
475         struct vm_area_struct *vma;
476 #if defined(__i386__)
477         unsigned int          pgprot;
478 #endif
479
480         if (offset > DRM_PROC_LIMIT) {
481                 *eof = 1;
482                 return 0;
483         }
484
485         *start = &buf[offset];
486         *eof   = 0;
487
488         DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
489                        atomic_read(&dev->vma_count),
490                        high_memory, virt_to_phys(high_memory));
491         for (pt = dev->vmalist; pt; pt = pt->next) {
492                 if (!(vma = pt->vma)) continue;
493                 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
494                                pt->pid,
495                                vma->vm_start,
496                                vma->vm_end,
497                                vma->vm_flags & VM_READ     ? 'r' : '-',
498                                vma->vm_flags & VM_WRITE    ? 'w' : '-',
499                                vma->vm_flags & VM_EXEC     ? 'x' : '-',
500                                vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
501                                vma->vm_flags & VM_LOCKED   ? 'l' : '-',
502                                vma->vm_flags & VM_IO       ? 'i' : '-',
503                                VM_OFFSET(vma));
504
505 #if defined(__i386__)
506                 pgprot = pgprot_val(vma->vm_page_prot);
507                 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
508                                pgprot & _PAGE_PRESENT  ? 'p' : '-',
509                                pgprot & _PAGE_RW       ? 'w' : 'r',
510                                pgprot & _PAGE_USER     ? 'u' : 's',
511                                pgprot & _PAGE_PWT      ? 't' : 'b',
512                                pgprot & _PAGE_PCD      ? 'u' : 'c',
513                                pgprot & _PAGE_ACCESSED ? 'a' : '-',
514                                pgprot & _PAGE_DIRTY    ? 'd' : '-',
515                                pgprot & _PAGE_PSE      ? 'm' : 'k',
516                                pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
517 #endif
518                 DRM_PROC_PRINT("\n");
519         }
520
521         if (len > request + offset) return request;
522         *eof = 1;
523         return len - offset;
524 }
525
526 static int drm_vma_info(char *buf, char **start, off_t offset, int request,
527                          int *eof, void *data)
528 {
529         drm_device_t *dev = (drm_device_t *)data;
530         int          ret;
531
532         down(&dev->struct_sem);
533         ret = drm__vma_info(buf, start, offset, request, eof, data);
534         up(&dev->struct_sem);
535         return ret;
536 }
537 #endif
538
539