drm: Add GEM ("graphics execution manager") to i915 driver.
[linux-3.10.git] / 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         DRM_PROC_PRINT("Current sequence: %d\n", i915_get_gem_seqno(dev));
196         DRM_PROC_PRINT("Waiter sequence:  %d\n",
197                        dev_priv->mm.waiting_gem_seqno);
198         DRM_PROC_PRINT("IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
199         if (len > request + offset)
200                 return request;
201         *eof = 1;
202         return len - offset;
203 }
204
205
206 static int i915_interrupt_info(char *buf, char **start, off_t offset,
207                                int request, int *eof, void *data)
208 {
209         struct drm_minor *minor = (struct drm_minor *) data;
210         struct drm_device *dev = minor->dev;
211         drm_i915_private_t *dev_priv = dev->dev_private;
212         int len = 0;
213
214         if (offset > DRM_PROC_LIMIT) {
215                 *eof = 1;
216                 return 0;
217         }
218
219         *start = &buf[offset];
220         *eof = 0;
221         DRM_PROC_PRINT("Interrupt enable:    %08x\n",
222                        I915_READ(IER));
223         DRM_PROC_PRINT("Interrupt identity:  %08x\n",
224                        I915_READ(IIR));
225         DRM_PROC_PRINT("Interrupt mask:      %08x\n",
226                        I915_READ(IMR));
227         DRM_PROC_PRINT("Pipe A stat:         %08x\n",
228                        I915_READ(PIPEASTAT));
229         DRM_PROC_PRINT("Pipe B stat:         %08x\n",
230                        I915_READ(PIPEBSTAT));
231         DRM_PROC_PRINT("Interrupts received: %d\n",
232                        atomic_read(&dev_priv->irq_received));
233         DRM_PROC_PRINT("Current sequence:    %d\n",
234                        i915_get_gem_seqno(dev));
235         DRM_PROC_PRINT("Waiter sequence:     %d\n",
236                        dev_priv->mm.waiting_gem_seqno);
237         DRM_PROC_PRINT("IRQ sequence:        %d\n",
238                        dev_priv->mm.irq_gem_seqno);
239         if (len > request + offset)
240                 return request;
241         *eof = 1;
242         return len - offset;
243 }
244
245 static struct drm_proc_list {
246         /** file name */
247         const char *name;
248         /** proc callback*/
249         int (*f) (char *, char **, off_t, int, int *, void *);
250 } i915_gem_proc_list[] = {
251         {"i915_gem_active", i915_gem_active_info},
252         {"i915_gem_flushing", i915_gem_flushing_info},
253         {"i915_gem_inactive", i915_gem_inactive_info},
254         {"i915_gem_request", i915_gem_request_info},
255         {"i915_gem_seqno", i915_gem_seqno_info},
256         {"i915_gem_interrupt", i915_interrupt_info},
257 };
258
259 #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
260
261 int i915_gem_proc_init(struct drm_minor *minor)
262 {
263         struct proc_dir_entry *ent;
264         int i, j;
265
266         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
267                 ent = create_proc_entry(i915_gem_proc_list[i].name,
268                                         S_IFREG | S_IRUGO, minor->dev_root);
269                 if (!ent) {
270                         DRM_ERROR("Cannot create /proc/dri/.../%s\n",
271                                   i915_gem_proc_list[i].name);
272                         for (j = 0; j < i; j++)
273                                 remove_proc_entry(i915_gem_proc_list[i].name,
274                                                   minor->dev_root);
275                         return -1;
276                 }
277                 ent->read_proc = i915_gem_proc_list[i].f;
278                 ent->data = minor;
279         }
280         return 0;
281 }
282
283 void i915_gem_proc_cleanup(struct drm_minor *minor)
284 {
285         int i;
286
287         if (!minor->dev_root)
288                 return;
289
290         for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
291                 remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
292 }