Merge commit 'v2.6.28-rc4' into timers/rtc
[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 %08x\n",
170                                gem_request->seqno,
171                                (int) (jiffies - gem_request->emitted_jiffies),
172                                gem_request->flush_domains);
173         }
174         if (len > request + offset)
175                 return request;
176         *eof = 1;
177         return len - offset;
178 }
179
180 static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
181                                int request, int *eof, void *data)
182 {
183         struct drm_minor *minor = (struct drm_minor *) data;
184         struct drm_device *dev = minor->dev;
185         drm_i915_private_t *dev_priv = dev->dev_private;
186         int len = 0;
187
188         if (offset > DRM_PROC_LIMIT) {
189                 *eof = 1;
190                 return 0;
191         }
192
193         *start = &buf[offset];
194         *eof = 0;
195         if (dev_priv->hw_status_page != NULL) {
196                 DRM_PROC_PRINT("Current sequence: %d\n",
197                                i915_get_gem_seqno(dev));
198         } else {
199                 DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
200         }
201         DRM_PROC_PRINT("Waiter sequence:  %d\n",
202                        dev_priv->mm.waiting_gem_seqno);
203         DRM_PROC_PRINT("IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
204         if (len > request + offset)
205                 return request;
206         *eof = 1;
207         return len - offset;
208 }
209
210
211 static int i915_interrupt_info(char *buf, char **start, off_t offset,
212                                int request, int *eof, void *data)
213 {
214         struct drm_minor *minor = (struct drm_minor *) data;
215         struct drm_device *dev = minor->dev;
216         drm_i915_private_t *dev_priv = dev->dev_private;
217         int len = 0;
218
219         if (offset > DRM_PROC_LIMIT) {
220                 *eof = 1;
221                 return 0;
222         }
223
224         *start = &buf[offset];
225         *eof = 0;
226         DRM_PROC_PRINT("Interrupt enable:    %08x\n",
227                        I915_READ(IER));
228         DRM_PROC_PRINT("Interrupt identity:  %08x\n",
229                        I915_READ(IIR));
230         DRM_PROC_PRINT("Interrupt mask:      %08x\n",
231                        I915_READ(IMR));
232         DRM_PROC_PRINT("Pipe A stat:         %08x\n",
233                        I915_READ(PIPEASTAT));
234         DRM_PROC_PRINT("Pipe B stat:         %08x\n",
235                        I915_READ(PIPEBSTAT));
236         DRM_PROC_PRINT("Interrupts received: %d\n",
237                        atomic_read(&dev_priv->irq_received));
238         if (dev_priv->hw_status_page != NULL) {
239                 DRM_PROC_PRINT("Current sequence:    %d\n",
240                                i915_get_gem_seqno(dev));
241         } else {
242                 DRM_PROC_PRINT("Current sequence:    hws uninitialized\n");
243         }
244         DRM_PROC_PRINT("Waiter sequence:     %d\n",
245                        dev_priv->mm.waiting_gem_seqno);
246         DRM_PROC_PRINT("IRQ sequence:        %d\n",
247                        dev_priv->mm.irq_gem_seqno);
248         if (len > request + offset)
249                 return request;
250         *eof = 1;
251         return len - offset;
252 }
253
254 static struct drm_proc_list {
255         /** file name */
256         const char *name;
257         /** proc callback*/
258         int (*f) (char *, char **, off_t, int, int *, void *);
259 } i915_gem_proc_list[] = {
260         {"i915_gem_active", i915_gem_active_info},
261         {"i915_gem_flushing", i915_gem_flushing_info},
262         {"i915_gem_inactive", i915_gem_inactive_info},
263         {"i915_gem_request", i915_gem_request_info},
264         {"i915_gem_seqno", i915_gem_seqno_info},
265         {"i915_gem_interrupt", i915_interrupt_info},
266 };
267
268 #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
269
270 int i915_gem_proc_init(struct drm_minor *minor)
271 {
272         struct proc_dir_entry *ent;
273         int i, j;
274
275         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
276                 ent = create_proc_entry(i915_gem_proc_list[i].name,
277                                         S_IFREG | S_IRUGO, minor->dev_root);
278                 if (!ent) {
279                         DRM_ERROR("Cannot create /proc/dri/.../%s\n",
280                                   i915_gem_proc_list[i].name);
281                         for (j = 0; j < i; j++)
282                                 remove_proc_entry(i915_gem_proc_list[i].name,
283                                                   minor->dev_root);
284                         return -1;
285                 }
286                 ent->read_proc = i915_gem_proc_list[i].f;
287                 ent->data = minor;
288         }
289         return 0;
290 }
291
292 void i915_gem_proc_cleanup(struct drm_minor *minor)
293 {
294         int i;
295
296         if (!minor->dev_root)
297                 return;
298
299         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
300                 remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
301 }