Merge branch 'next' into for-linus
[linux-2.6] / drivers / gpu / drm / i915 / i915_gem_proc.c
1 /*
2  * Copyright © 2008 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Keith Packard <keithp@keithp.com>
26  *
27  */
28
29 #include "drmP.h"
30 #include "drm.h"
31 #include "i915_drm.h"
32 #include "i915_drv.h"
33
34 static int i915_gem_active_info(char *buf, char **start, off_t offset,
35                                 int request, int *eof, void *data)
36 {
37         struct drm_minor *minor = (struct drm_minor *) data;
38         struct drm_device *dev = minor->dev;
39         drm_i915_private_t *dev_priv = dev->dev_private;
40         struct drm_i915_gem_object *obj_priv;
41         int len = 0;
42
43         if (offset > DRM_PROC_LIMIT) {
44                 *eof = 1;
45                 return 0;
46         }
47
48         *start = &buf[offset];
49         *eof = 0;
50         DRM_PROC_PRINT("Active:\n");
51         list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
52                             list)
53         {
54                 struct drm_gem_object *obj = obj_priv->obj;
55                 if (obj->name) {
56                         DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
57                                        obj, obj->name,
58                                        obj->read_domains, obj->write_domain,
59                                        obj_priv->last_rendering_seqno);
60                 } else {
61                         DRM_PROC_PRINT("       %p: %08x %08x %d\n",
62                                        obj,
63                                        obj->read_domains, obj->write_domain,
64                                        obj_priv->last_rendering_seqno);
65                 }
66         }
67         if (len > request + offset)
68                 return request;
69         *eof = 1;
70         return len - offset;
71 }
72
73 static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
74                                   int request, int *eof, void *data)
75 {
76         struct drm_minor *minor = (struct drm_minor *) data;
77         struct drm_device *dev = minor->dev;
78         drm_i915_private_t *dev_priv = dev->dev_private;
79         struct drm_i915_gem_object *obj_priv;
80         int len = 0;
81
82         if (offset > DRM_PROC_LIMIT) {
83                 *eof = 1;
84                 return 0;
85         }
86
87         *start = &buf[offset];
88         *eof = 0;
89         DRM_PROC_PRINT("Flushing:\n");
90         list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
91                             list)
92         {
93                 struct drm_gem_object *obj = obj_priv->obj;
94                 if (obj->name) {
95                         DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
96                                        obj, obj->name,
97                                        obj->read_domains, obj->write_domain,
98                                        obj_priv->last_rendering_seqno);
99                 } else {
100                         DRM_PROC_PRINT("       %p: %08x %08x %d\n", obj,
101                                        obj->read_domains, obj->write_domain,
102                                        obj_priv->last_rendering_seqno);
103                 }
104         }
105         if (len > request + offset)
106                 return request;
107         *eof = 1;
108         return len - offset;
109 }
110
111 static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
112                                   int request, int *eof, void *data)
113 {
114         struct drm_minor *minor = (struct drm_minor *) data;
115         struct drm_device *dev = minor->dev;
116         drm_i915_private_t *dev_priv = dev->dev_private;
117         struct drm_i915_gem_object *obj_priv;
118         int len = 0;
119
120         if (offset > DRM_PROC_LIMIT) {
121                 *eof = 1;
122                 return 0;
123         }
124
125         *start = &buf[offset];
126         *eof = 0;
127         DRM_PROC_PRINT("Inactive:\n");
128         list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
129                             list)
130         {
131                 struct drm_gem_object *obj = obj_priv->obj;
132                 if (obj->name) {
133                         DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
134                                        obj, obj->name,
135                                        obj->read_domains, obj->write_domain,
136                                        obj_priv->last_rendering_seqno);
137                 } else {
138                         DRM_PROC_PRINT("       %p: %08x %08x %d\n", obj,
139                                        obj->read_domains, obj->write_domain,
140                                        obj_priv->last_rendering_seqno);
141                 }
142         }
143         if (len > request + offset)
144                 return request;
145         *eof = 1;
146         return len - offset;
147 }
148
149 static int i915_gem_request_info(char *buf, char **start, off_t offset,
150                                  int request, int *eof, void *data)
151 {
152         struct drm_minor *minor = (struct drm_minor *) data;
153         struct drm_device *dev = minor->dev;
154         drm_i915_private_t *dev_priv = dev->dev_private;
155         struct drm_i915_gem_request *gem_request;
156         int len = 0;
157
158         if (offset > DRM_PROC_LIMIT) {
159                 *eof = 1;
160                 return 0;
161         }
162
163         *start = &buf[offset];
164         *eof = 0;
165         DRM_PROC_PRINT("Request:\n");
166         list_for_each_entry(gem_request, &dev_priv->mm.request_list,
167                             list)
168         {
169                 DRM_PROC_PRINT("    %d @ %d\n",
170                                gem_request->seqno,
171                                (int) (jiffies - gem_request->emitted_jiffies));
172         }
173         if (len > request + offset)
174                 return request;
175         *eof = 1;
176         return len - offset;
177 }
178
179 static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
180                                int request, int *eof, void *data)
181 {
182         struct drm_minor *minor = (struct drm_minor *) data;
183         struct drm_device *dev = minor->dev;
184         drm_i915_private_t *dev_priv = dev->dev_private;
185         int len = 0;
186
187         if (offset > DRM_PROC_LIMIT) {
188                 *eof = 1;
189                 return 0;
190         }
191
192         *start = &buf[offset];
193         *eof = 0;
194         if (dev_priv->hw_status_page != NULL) {
195                 DRM_PROC_PRINT("Current sequence: %d\n",
196                                i915_get_gem_seqno(dev));
197         } else {
198                 DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
199         }
200         DRM_PROC_PRINT("Waiter sequence:  %d\n",
201                        dev_priv->mm.waiting_gem_seqno);
202         DRM_PROC_PRINT("IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
203         if (len > request + offset)
204                 return request;
205         *eof = 1;
206         return len - offset;
207 }
208
209
210 static int i915_interrupt_info(char *buf, char **start, off_t offset,
211                                int request, int *eof, void *data)
212 {
213         struct drm_minor *minor = (struct drm_minor *) data;
214         struct drm_device *dev = minor->dev;
215         drm_i915_private_t *dev_priv = dev->dev_private;
216         int len = 0;
217
218         if (offset > DRM_PROC_LIMIT) {
219                 *eof = 1;
220                 return 0;
221         }
222
223         *start = &buf[offset];
224         *eof = 0;
225         DRM_PROC_PRINT("Interrupt enable:    %08x\n",
226                        I915_READ(IER));
227         DRM_PROC_PRINT("Interrupt identity:  %08x\n",
228                        I915_READ(IIR));
229         DRM_PROC_PRINT("Interrupt mask:      %08x\n",
230                        I915_READ(IMR));
231         DRM_PROC_PRINT("Pipe A stat:         %08x\n",
232                        I915_READ(PIPEASTAT));
233         DRM_PROC_PRINT("Pipe B stat:         %08x\n",
234                        I915_READ(PIPEBSTAT));
235         DRM_PROC_PRINT("Interrupts received: %d\n",
236                        atomic_read(&dev_priv->irq_received));
237         if (dev_priv->hw_status_page != NULL) {
238                 DRM_PROC_PRINT("Current sequence:    %d\n",
239                                i915_get_gem_seqno(dev));
240         } else {
241                 DRM_PROC_PRINT("Current sequence:    hws uninitialized\n");
242         }
243         DRM_PROC_PRINT("Waiter sequence:     %d\n",
244                        dev_priv->mm.waiting_gem_seqno);
245         DRM_PROC_PRINT("IRQ sequence:        %d\n",
246                        dev_priv->mm.irq_gem_seqno);
247         if (len > request + offset)
248                 return request;
249         *eof = 1;
250         return len - offset;
251 }
252
253 static struct drm_proc_list {
254         /** file name */
255         const char *name;
256         /** proc callback*/
257         int (*f) (char *, char **, off_t, int, int *, void *);
258 } i915_gem_proc_list[] = {
259         {"i915_gem_active", i915_gem_active_info},
260         {"i915_gem_flushing", i915_gem_flushing_info},
261         {"i915_gem_inactive", i915_gem_inactive_info},
262         {"i915_gem_request", i915_gem_request_info},
263         {"i915_gem_seqno", i915_gem_seqno_info},
264         {"i915_gem_interrupt", i915_interrupt_info},
265 };
266
267 #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
268
269 int i915_gem_proc_init(struct drm_minor *minor)
270 {
271         struct proc_dir_entry *ent;
272         int i, j;
273
274         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
275                 ent = create_proc_entry(i915_gem_proc_list[i].name,
276                                         S_IFREG | S_IRUGO, minor->dev_root);
277                 if (!ent) {
278                         DRM_ERROR("Cannot create /proc/dri/.../%s\n",
279                                   i915_gem_proc_list[i].name);
280                         for (j = 0; j < i; j++)
281                                 remove_proc_entry(i915_gem_proc_list[i].name,
282                                                   minor->dev_root);
283                         return -1;
284                 }
285                 ent->read_proc = i915_gem_proc_list[i].f;
286                 ent->data = minor;
287         }
288         return 0;
289 }
290
291 void i915_gem_proc_cleanup(struct drm_minor *minor)
292 {
293         int i;
294
295         if (!minor->dev_root)
296                 return;
297
298         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
299                 remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
300 }