drm: updated DRM map patch for 32/64 bit systems
[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 static 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 and _DRM_CONSISTENT */
214         const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
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)
233                         continue;
234                 if (map->type < 0 || map->type > 5)
235                         type = "??";
236                 else    
237                         type = types[map->type];
238                 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08x ",
239                                i,
240                                map->offset,
241                                map->size,
242                                type,
243                                map->flags,
244                                r_list->user_token);
245                 if (map->mtrr < 0) {
246                         DRM_PROC_PRINT("none\n");
247                 } else {
248                         DRM_PROC_PRINT("%4d\n", map->mtrr);
249                 }
250                 i++;
251         }
252
253         if (len > request + offset) return request;
254         *eof = 1;
255         return len - offset;
256 }
257
258 /**
259  * Simply calls _vm_info() while holding the drm_device::struct_sem lock.
260  */
261 static int drm_vm_info(char *buf, char **start, off_t offset, int request,
262                         int *eof, void *data)
263 {
264         drm_device_t *dev = (drm_device_t *)data;
265         int          ret;
266
267         down(&dev->struct_sem);
268         ret = drm__vm_info(buf, start, offset, request, eof, data);
269         up(&dev->struct_sem);
270         return ret;
271 }
272
273 /**
274  * Called when "/proc/dri/.../queues" is read.
275  * 
276  * \param buf output buffer.
277  * \param start start of output data.
278  * \param offset requested start offset.
279  * \param request requested number of bytes.
280  * \param eof whether there is no more data to return.
281  * \param data private data.
282  * \return number of written bytes.
283  */
284 static int drm__queues_info(char *buf, char **start, off_t offset,
285                              int request, int *eof, void *data)
286 {
287         drm_device_t *dev = (drm_device_t *)data;
288         int          len  = 0;
289         int          i;
290         drm_queue_t  *q;
291
292         if (offset > DRM_PROC_LIMIT) {
293                 *eof = 1;
294                 return 0;
295         }
296
297         *start = &buf[offset];
298         *eof   = 0;
299
300         DRM_PROC_PRINT("  ctx/flags   use   fin"
301                        "   blk/rw/rwf  wait    flushed     queued"
302                        "      locks\n\n");
303         for (i = 0; i < dev->queue_count; i++) {
304                 q = dev->queuelist[i];
305                 atomic_inc(&q->use_count);
306                 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
307                                    "%5d/0x%03x %5d %5d"
308                                    " %5d/%c%c/%c%c%c %5Zd\n",
309                                    i,
310                                    q->flags,
311                                    atomic_read(&q->use_count),
312                                    atomic_read(&q->finalization),
313                                    atomic_read(&q->block_count),
314                                    atomic_read(&q->block_read) ? 'r' : '-',
315                                    atomic_read(&q->block_write) ? 'w' : '-',
316                                    waitqueue_active(&q->read_queue) ? 'r':'-',
317                                    waitqueue_active(&q->write_queue) ? 'w':'-',
318                                    waitqueue_active(&q->flush_queue) ? 'f':'-',
319                                    DRM_BUFCOUNT(&q->waitlist));
320                 atomic_dec(&q->use_count);
321         }
322
323         if (len > request + offset) return request;
324         *eof = 1;
325         return len - offset;
326 }
327
328 /**
329  * Simply calls _queues_info() while holding the drm_device::struct_sem lock.
330  */
331 static int drm_queues_info(char *buf, char **start, off_t offset, int request,
332                             int *eof, void *data)
333 {
334         drm_device_t *dev = (drm_device_t *)data;
335         int          ret;
336
337         down(&dev->struct_sem);
338         ret = drm__queues_info(buf, start, offset, request, eof, data);
339         up(&dev->struct_sem);
340         return ret;
341 }
342
343 /**
344  * Called when "/proc/dri/.../bufs" is read.
345  * 
346  * \param buf output buffer.
347  * \param start start of output data.
348  * \param offset requested start offset.
349  * \param request requested number of bytes.
350  * \param eof whether there is no more data to return.
351  * \param data private data.
352  * \return number of written bytes.
353  */
354 static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
355                            int *eof, void *data)
356 {
357         drm_device_t     *dev = (drm_device_t *)data;
358         int              len  = 0;
359         drm_device_dma_t *dma = dev->dma;
360         int              i;
361
362         if (!dma || offset > DRM_PROC_LIMIT) {
363                 *eof = 1;
364                 return 0;
365         }
366
367         *start = &buf[offset];
368         *eof   = 0;
369
370         DRM_PROC_PRINT(" o     size count  free  segs pages    kB\n\n");
371         for (i = 0; i <= DRM_MAX_ORDER; i++) {
372                 if (dma->bufs[i].buf_count)
373                         DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
374                                        i,
375                                        dma->bufs[i].buf_size,
376                                        dma->bufs[i].buf_count,
377                                        atomic_read(&dma->bufs[i]
378                                                    .freelist.count),
379                                        dma->bufs[i].seg_count,
380                                        dma->bufs[i].seg_count
381                                        *(1 << dma->bufs[i].page_order),
382                                        (dma->bufs[i].seg_count
383                                         * (1 << dma->bufs[i].page_order))
384                                        * PAGE_SIZE / 1024);
385         }
386         DRM_PROC_PRINT("\n");
387         for (i = 0; i < dma->buf_count; i++) {
388                 if (i && !(i%32)) DRM_PROC_PRINT("\n");
389                 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
390         }
391         DRM_PROC_PRINT("\n");
392
393         if (len > request + offset) return request;
394         *eof = 1;
395         return len - offset;
396 }
397
398 /**
399  * Simply calls _bufs_info() while holding the drm_device::struct_sem lock.
400  */
401 static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
402                           int *eof, void *data)
403 {
404         drm_device_t *dev = (drm_device_t *)data;
405         int          ret;
406
407         down(&dev->struct_sem);
408         ret = drm__bufs_info(buf, start, offset, request, eof, data);
409         up(&dev->struct_sem);
410         return ret;
411 }
412
413 /**
414  * Called when "/proc/dri/.../clients" is read.
415  * 
416  * \param buf output buffer.
417  * \param start start of output data.
418  * \param offset requested start offset.
419  * \param request requested number of bytes.
420  * \param eof whether there is no more data to return.
421  * \param data private data.
422  * \return number of written bytes.
423  */
424 static int drm__clients_info(char *buf, char **start, off_t offset,
425                               int request, int *eof, void *data)
426 {
427         drm_device_t *dev = (drm_device_t *)data;
428         int          len  = 0;
429         drm_file_t   *priv;
430
431         if (offset > DRM_PROC_LIMIT) {
432                 *eof = 1;
433                 return 0;
434         }
435
436         *start = &buf[offset];
437         *eof   = 0;
438
439         DRM_PROC_PRINT("a dev   pid    uid      magic     ioctls\n\n");
440         for (priv = dev->file_first; priv; priv = priv->next) {
441                 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
442                                priv->authenticated ? 'y' : 'n',
443                                priv->minor,
444                                priv->pid,
445                                priv->uid,
446                                priv->magic,
447                                priv->ioctl_count);
448         }
449
450         if (len > request + offset) return request;
451         *eof = 1;
452         return len - offset;
453 }
454
455 /**
456  * Simply calls _clients_info() while holding the drm_device::struct_sem lock.
457  */
458 static int drm_clients_info(char *buf, char **start, off_t offset,
459                              int request, int *eof, void *data)
460 {
461         drm_device_t *dev = (drm_device_t *)data;
462         int          ret;
463
464         down(&dev->struct_sem);
465         ret = drm__clients_info(buf, start, offset, request, eof, data);
466         up(&dev->struct_sem);
467         return ret;
468 }
469
470 #if DRM_DEBUG_CODE
471
472 static int drm__vma_info(char *buf, char **start, off_t offset, int request,
473                           int *eof, void *data)
474 {
475         drm_device_t          *dev = (drm_device_t *)data;
476         int                   len  = 0;
477         drm_vma_entry_t       *pt;
478         struct vm_area_struct *vma;
479 #if defined(__i386__)
480         unsigned int          pgprot;
481 #endif
482
483         if (offset > DRM_PROC_LIMIT) {
484                 *eof = 1;
485                 return 0;
486         }
487
488         *start = &buf[offset];
489         *eof   = 0;
490
491         DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
492                        atomic_read(&dev->vma_count),
493                        high_memory, virt_to_phys(high_memory));
494         for (pt = dev->vmalist; pt; pt = pt->next) {
495                 if (!(vma = pt->vma)) continue;
496                 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
497                                pt->pid,
498                                vma->vm_start,
499                                vma->vm_end,
500                                vma->vm_flags & VM_READ     ? 'r' : '-',
501                                vma->vm_flags & VM_WRITE    ? 'w' : '-',
502                                vma->vm_flags & VM_EXEC     ? 'x' : '-',
503                                vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
504                                vma->vm_flags & VM_LOCKED   ? 'l' : '-',
505                                vma->vm_flags & VM_IO       ? 'i' : '-',
506                                VM_OFFSET(vma));
507
508 #if defined(__i386__)
509                 pgprot = pgprot_val(vma->vm_page_prot);
510                 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
511                                pgprot & _PAGE_PRESENT  ? 'p' : '-',
512                                pgprot & _PAGE_RW       ? 'w' : 'r',
513                                pgprot & _PAGE_USER     ? 'u' : 's',
514                                pgprot & _PAGE_PWT      ? 't' : 'b',
515                                pgprot & _PAGE_PCD      ? 'u' : 'c',
516                                pgprot & _PAGE_ACCESSED ? 'a' : '-',
517                                pgprot & _PAGE_DIRTY    ? 'd' : '-',
518                                pgprot & _PAGE_PSE      ? 'm' : 'k',
519                                pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
520 #endif
521                 DRM_PROC_PRINT("\n");
522         }
523
524         if (len > request + offset) return request;
525         *eof = 1;
526         return len - offset;
527 }
528
529 static int drm_vma_info(char *buf, char **start, off_t offset, int request,
530                          int *eof, void *data)
531 {
532         drm_device_t *dev = (drm_device_t *)data;
533         int          ret;
534
535         down(&dev->struct_sem);
536         ret = drm__vma_info(buf, start, offset, request, eof, data);
537         up(&dev->struct_sem);
538         return ret;
539 }
540 #endif
541
542