diff options
Diffstat (limited to 'drivers/gpu/drm/drm_proc.c')
-rw-r--r-- | drivers/gpu/drm/drm_proc.c | 721 |
1 files changed, 110 insertions, 611 deletions
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index b756f043a5f4..9b3c5af61e98 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c | |||
@@ -37,697 +37,196 @@ | |||
37 | * OTHER DEALINGS IN THE SOFTWARE. | 37 | * OTHER DEALINGS IN THE SOFTWARE. |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/seq_file.h> | ||
40 | #include "drmP.h" | 41 | #include "drmP.h" |
41 | 42 | ||
42 | static int drm_name_info(char *buf, char **start, off_t offset, | 43 | |
43 | int request, int *eof, void *data); | 44 | /*************************************************** |
44 | static int drm_vm_info(char *buf, char **start, off_t offset, | 45 | * Initialization, etc. |
45 | int request, int *eof, void *data); | 46 | **************************************************/ |
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 | static int drm_vblank_info(char *buf, char **start, off_t offset, | ||
53 | int request, int *eof, void *data); | ||
54 | static int drm_gem_name_info(char *buf, char **start, off_t offset, | ||
55 | int request, int *eof, void *data); | ||
56 | static int drm_gem_object_info(char *buf, char **start, off_t offset, | ||
57 | int request, int *eof, void *data); | ||
58 | #if DRM_DEBUG_CODE | ||
59 | static int drm_vma_info(char *buf, char **start, off_t offset, | ||
60 | int request, int *eof, void *data); | ||
61 | #endif | ||
62 | 47 | ||
63 | /** | 48 | /** |
64 | * Proc file list. | 49 | * Proc file list. |
65 | */ | 50 | */ |
66 | static struct drm_proc_list { | 51 | static struct drm_info_list drm_proc_list[] = { |
67 | const char *name; /**< file name */ | ||
68 | int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ | ||
69 | u32 driver_features; /**< Required driver features for this entry */ | ||
70 | } drm_proc_list[] = { | ||
71 | {"name", drm_name_info, 0}, | 52 | {"name", drm_name_info, 0}, |
72 | {"mem", drm_mem_info, 0}, | ||
73 | {"vm", drm_vm_info, 0}, | 53 | {"vm", drm_vm_info, 0}, |
74 | {"clients", drm_clients_info, 0}, | 54 | {"clients", drm_clients_info, 0}, |
75 | {"queues", drm_queues_info, 0}, | 55 | {"queues", drm_queues_info, 0}, |
76 | {"bufs", drm_bufs_info, 0}, | 56 | {"bufs", drm_bufs_info, 0}, |
77 | {"vblank", drm_vblank_info, 0}, | ||
78 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, | 57 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, |
79 | {"gem_objects", drm_gem_object_info, DRIVER_GEM}, | 58 | {"gem_objects", drm_gem_object_info, DRIVER_GEM}, |
80 | #if DRM_DEBUG_CODE | 59 | #if DRM_DEBUG_CODE |
81 | {"vma", drm_vma_info}, | 60 | {"vma", drm_vma_info, 0}, |
82 | #endif | 61 | #endif |
83 | }; | 62 | }; |
84 | |||
85 | #define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) | 63 | #define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) |
86 | 64 | ||
65 | static int drm_proc_open(struct inode *inode, struct file *file) | ||
66 | { | ||
67 | struct drm_info_node* node = PDE(inode)->data; | ||
68 | |||
69 | return single_open(file, node->info_ent->show, node); | ||
70 | } | ||
71 | |||
72 | static const struct file_operations drm_proc_fops = { | ||
73 | .owner = THIS_MODULE, | ||
74 | .open = drm_proc_open, | ||
75 | .read = seq_read, | ||
76 | .llseek = seq_lseek, | ||
77 | .release = single_release, | ||
78 | }; | ||
79 | |||
80 | |||
87 | /** | 81 | /** |
88 | * Initialize the DRI proc filesystem for a device. | 82 | * Initialize a given set of proc files for a device |
89 | * | 83 | * |
90 | * \param dev DRM device. | 84 | * \param files The array of files to create |
91 | * \param minor device minor number. | 85 | * \param count The number of files given |
92 | * \param root DRI proc dir entry. | 86 | * \param root DRI proc dir entry. |
93 | * \param dev_root resulting DRI device proc dir entry. | 87 | * \param minor device minor number |
94 | * \return root entry pointer on success, or NULL on failure. | 88 | * \return Zero on success, non-zero on failure |
95 | * | 89 | * |
96 | * Create the DRI proc root entry "/proc/dri", the device proc root entry | 90 | * Create a given set of proc files represented by an array of |
97 | * "/proc/dri/%minor%/", and each entry in proc_list as | 91 | * gdm_proc_lists in the given root directory. |
98 | * "/proc/dri/%minor%/%name%". | ||
99 | */ | 92 | */ |
100 | int drm_proc_init(struct drm_minor *minor, int minor_id, | 93 | int drm_proc_create_files(struct drm_info_list *files, int count, |
101 | struct proc_dir_entry *root) | 94 | struct proc_dir_entry *root, struct drm_minor *minor) |
102 | { | 95 | { |
103 | struct drm_device *dev = minor->dev; | 96 | struct drm_device *dev = minor->dev; |
104 | struct proc_dir_entry *ent; | 97 | struct proc_dir_entry *ent; |
105 | int i, j, ret; | 98 | struct drm_info_node *tmp; |
106 | char name[64]; | 99 | char name[64]; |
100 | int i, ret; | ||
107 | 101 | ||
108 | sprintf(name, "%d", minor_id); | 102 | for (i = 0; i < count; i++) { |
109 | minor->dev_root = proc_mkdir(name, root); | 103 | u32 features = files[i].driver_features; |
110 | if (!minor->dev_root) { | ||
111 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | for (i = 0; i < DRM_PROC_ENTRIES; i++) { | ||
116 | u32 features = drm_proc_list[i].driver_features; | ||
117 | 104 | ||
118 | if (features != 0 && | 105 | if (features != 0 && |
119 | (dev->driver->driver_features & features) != features) | 106 | (dev->driver->driver_features & features) != features) |
120 | continue; | 107 | continue; |
121 | 108 | ||
122 | ent = create_proc_entry(drm_proc_list[i].name, | 109 | tmp = drm_alloc(sizeof(struct drm_info_node), _DRM_DRIVER); |
123 | S_IFREG | S_IRUGO, minor->dev_root); | 110 | ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root); |
124 | if (!ent) { | 111 | if (!ent) { |
125 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", | 112 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", |
126 | name, drm_proc_list[i].name); | 113 | name, files[i].name); |
114 | drm_free(tmp, sizeof(struct drm_info_node), | ||
115 | _DRM_DRIVER); | ||
127 | ret = -1; | 116 | ret = -1; |
128 | goto fail; | 117 | goto fail; |
129 | } | 118 | } |
130 | ent->read_proc = drm_proc_list[i].f; | ||
131 | ent->data = minor; | ||
132 | } | ||
133 | 119 | ||
134 | if (dev->driver->proc_init) { | 120 | ent->proc_fops = &drm_proc_fops; |
135 | ret = dev->driver->proc_init(minor); | 121 | ent->data = tmp; |
136 | if (ret) { | 122 | tmp->minor = minor; |
137 | DRM_ERROR("DRM: Driver failed to initialize " | 123 | tmp->info_ent = &files[i]; |
138 | "/proc/dri.\n"); | 124 | list_add(&(tmp->list), &(minor->proc_nodes.list)); |
139 | goto fail; | ||
140 | } | ||
141 | } | 125 | } |
142 | |||
143 | return 0; | 126 | return 0; |
144 | fail: | ||
145 | 127 | ||
146 | for (j = 0; j < i; j++) | 128 | fail: |
147 | remove_proc_entry(drm_proc_list[i].name, | 129 | for (i = 0; i < count; i++) |
148 | minor->dev_root); | 130 | remove_proc_entry(drm_proc_list[i].name, minor->proc_root); |
149 | remove_proc_entry(name, root); | ||
150 | minor->dev_root = NULL; | ||
151 | return ret; | 131 | return ret; |
152 | } | 132 | } |
153 | 133 | ||
154 | /** | 134 | /** |
155 | * Cleanup the proc filesystem resources. | 135 | * Initialize the DRI proc filesystem for a device |
156 | * | 136 | * |
157 | * \param minor device minor number. | 137 | * \param dev DRM device |
138 | * \param minor device minor number | ||
158 | * \param root DRI proc dir entry. | 139 | * \param root DRI proc dir entry. |
159 | * \param dev_root DRI device proc dir entry. | 140 | * \param dev_root resulting DRI device proc dir entry. |
160 | * \return always zero. | 141 | * \return root entry pointer on success, or NULL on failure. |
161 | * | 142 | * |
162 | * Remove all proc entries created by proc_init(). | 143 | * Create the DRI proc root entry "/proc/dri", the device proc root entry |
144 | * "/proc/dri/%minor%/", and each entry in proc_list as | ||
145 | * "/proc/dri/%minor%/%name%". | ||
163 | */ | 146 | */ |
164 | int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) | 147 | int drm_proc_init(struct drm_minor *minor, int minor_id, |
148 | struct proc_dir_entry *root) | ||
165 | { | 149 | { |
166 | struct drm_device *dev = minor->dev; | 150 | struct drm_device *dev = minor->dev; |
167 | int i; | ||
168 | char name[64]; | 151 | char name[64]; |
152 | int ret; | ||
169 | 153 | ||
170 | if (!root || !minor->dev_root) | 154 | INIT_LIST_HEAD(&minor->proc_nodes.list); |
171 | return 0; | 155 | sprintf(name, "%d", minor_id); |
172 | 156 | minor->proc_root = proc_mkdir(name, root); | |
173 | if (dev->driver->proc_cleanup) | 157 | if (!minor->proc_root) { |
174 | dev->driver->proc_cleanup(minor); | 158 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); |
175 | 159 | return -1; | |
176 | for (i = 0; i < DRM_PROC_ENTRIES; i++) | ||
177 | remove_proc_entry(drm_proc_list[i].name, minor->dev_root); | ||
178 | sprintf(name, "%d", minor->index); | ||
179 | remove_proc_entry(name, root); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * Called when "/proc/dri/.../name" is read. | ||
186 | * | ||
187 | * \param buf output buffer. | ||
188 | * \param start start of output data. | ||
189 | * \param offset requested start offset. | ||
190 | * \param request requested number of bytes. | ||
191 | * \param eof whether there is no more data to return. | ||
192 | * \param data private data. | ||
193 | * \return number of written bytes. | ||
194 | * | ||
195 | * Prints the device name together with the bus id if available. | ||
196 | */ | ||
197 | static int drm_name_info(char *buf, char **start, off_t offset, int request, | ||
198 | int *eof, void *data) | ||
199 | { | ||
200 | struct drm_minor *minor = (struct drm_minor *) data; | ||
201 | struct drm_master *master = minor->master; | ||
202 | struct drm_device *dev = minor->dev; | ||
203 | int len = 0; | ||
204 | |||
205 | if (offset > DRM_PROC_LIMIT) { | ||
206 | *eof = 1; | ||
207 | return 0; | ||
208 | } | 160 | } |
209 | 161 | ||
210 | if (!master) | 162 | ret = drm_proc_create_files(drm_proc_list, DRM_PROC_ENTRIES, |
211 | return 0; | 163 | minor->proc_root, minor); |
212 | 164 | if (ret) { | |
213 | *start = &buf[offset]; | 165 | remove_proc_entry(name, root); |
214 | *eof = 0; | 166 | minor->proc_root = NULL; |
215 | 167 | DRM_ERROR("Failed to create core drm proc files\n"); | |
216 | if (master->unique) { | 168 | return ret; |
217 | DRM_PROC_PRINT("%s %s %s\n", | ||
218 | dev->driver->pci_driver.name, | ||
219 | pci_name(dev->pdev), master->unique); | ||
220 | } else { | ||
221 | DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, | ||
222 | pci_name(dev->pdev)); | ||
223 | } | 169 | } |
224 | 170 | ||
225 | if (len > request + offset) | 171 | if (dev->driver->proc_init) { |
226 | return request; | 172 | ret = dev->driver->proc_init(minor); |
227 | *eof = 1; | 173 | if (ret) { |
228 | return len - offset; | 174 | DRM_ERROR("DRM: Driver failed to initialize " |
229 | } | 175 | "/proc/dri.\n"); |
230 | 176 | return ret; | |
231 | /** | ||
232 | * Called when "/proc/dri/.../vm" is read. | ||
233 | * | ||
234 | * \param buf output buffer. | ||
235 | * \param start start of output data. | ||
236 | * \param offset requested start offset. | ||
237 | * \param request requested number of bytes. | ||
238 | * \param eof whether there is no more data to return. | ||
239 | * \param data private data. | ||
240 | * \return number of written bytes. | ||
241 | * | ||
242 | * Prints information about all mappings in drm_device::maplist. | ||
243 | */ | ||
244 | static int drm__vm_info(char *buf, char **start, off_t offset, int request, | ||
245 | int *eof, void *data) | ||
246 | { | ||
247 | struct drm_minor *minor = (struct drm_minor *) data; | ||
248 | struct drm_device *dev = minor->dev; | ||
249 | int len = 0; | ||
250 | struct drm_map *map; | ||
251 | struct drm_map_list *r_list; | ||
252 | |||
253 | /* Hardcoded from _DRM_FRAME_BUFFER, | ||
254 | _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and | ||
255 | _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ | ||
256 | const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; | ||
257 | const char *type; | ||
258 | int i; | ||
259 | |||
260 | if (offset > DRM_PROC_LIMIT) { | ||
261 | *eof = 1; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | *start = &buf[offset]; | ||
266 | *eof = 0; | ||
267 | |||
268 | DRM_PROC_PRINT("slot offset size type flags " | ||
269 | "address mtrr\n\n"); | ||
270 | i = 0; | ||
271 | list_for_each_entry(r_list, &dev->maplist, head) { | ||
272 | map = r_list->map; | ||
273 | if (!map) | ||
274 | continue; | ||
275 | if (map->type < 0 || map->type > 5) | ||
276 | type = "??"; | ||
277 | else | ||
278 | type = types[map->type]; | ||
279 | DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", | ||
280 | i, | ||
281 | map->offset, | ||
282 | map->size, type, map->flags, | ||
283 | (unsigned long) r_list->user_token); | ||
284 | if (map->mtrr < 0) { | ||
285 | DRM_PROC_PRINT("none\n"); | ||
286 | } else { | ||
287 | DRM_PROC_PRINT("%4d\n", map->mtrr); | ||
288 | } | 177 | } |
289 | i++; | ||
290 | } | ||
291 | |||
292 | if (len > request + offset) | ||
293 | return request; | ||
294 | *eof = 1; | ||
295 | return len - offset; | ||
296 | } | ||
297 | |||
298 | /** | ||
299 | * Simply calls _vm_info() while holding the drm_device::struct_mutex lock. | ||
300 | */ | ||
301 | static int drm_vm_info(char *buf, char **start, off_t offset, int request, | ||
302 | int *eof, void *data) | ||
303 | { | ||
304 | struct drm_minor *minor = (struct drm_minor *) data; | ||
305 | struct drm_device *dev = minor->dev; | ||
306 | int ret; | ||
307 | |||
308 | mutex_lock(&dev->struct_mutex); | ||
309 | ret = drm__vm_info(buf, start, offset, request, eof, data); | ||
310 | mutex_unlock(&dev->struct_mutex); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * Called when "/proc/dri/.../queues" is read. | ||
316 | * | ||
317 | * \param buf output buffer. | ||
318 | * \param start start of output data. | ||
319 | * \param offset requested start offset. | ||
320 | * \param request requested number of bytes. | ||
321 | * \param eof whether there is no more data to return. | ||
322 | * \param data private data. | ||
323 | * \return number of written bytes. | ||
324 | */ | ||
325 | static int drm__queues_info(char *buf, char **start, off_t offset, | ||
326 | int request, int *eof, void *data) | ||
327 | { | ||
328 | struct drm_minor *minor = (struct drm_minor *) data; | ||
329 | struct drm_device *dev = minor->dev; | ||
330 | int len = 0; | ||
331 | int i; | ||
332 | struct drm_queue *q; | ||
333 | |||
334 | if (offset > DRM_PROC_LIMIT) { | ||
335 | *eof = 1; | ||
336 | return 0; | ||
337 | } | 178 | } |
338 | 179 | return 0; | |
339 | *start = &buf[offset]; | ||
340 | *eof = 0; | ||
341 | |||
342 | DRM_PROC_PRINT(" ctx/flags use fin" | ||
343 | " blk/rw/rwf wait flushed queued" | ||
344 | " locks\n\n"); | ||
345 | for (i = 0; i < dev->queue_count; i++) { | ||
346 | q = dev->queuelist[i]; | ||
347 | atomic_inc(&q->use_count); | ||
348 | DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), | ||
349 | "%5d/0x%03x %5d %5d" | ||
350 | " %5d/%c%c/%c%c%c %5Zd\n", | ||
351 | i, | ||
352 | q->flags, | ||
353 | atomic_read(&q->use_count), | ||
354 | atomic_read(&q->finalization), | ||
355 | atomic_read(&q->block_count), | ||
356 | atomic_read(&q->block_read) ? 'r' : '-', | ||
357 | atomic_read(&q->block_write) ? 'w' : '-', | ||
358 | waitqueue_active(&q->read_queue) ? 'r' : '-', | ||
359 | waitqueue_active(&q-> | ||
360 | write_queue) ? 'w' : '-', | ||
361 | waitqueue_active(&q-> | ||
362 | flush_queue) ? 'f' : '-', | ||
363 | DRM_BUFCOUNT(&q->waitlist)); | ||
364 | atomic_dec(&q->use_count); | ||
365 | } | ||
366 | |||
367 | if (len > request + offset) | ||
368 | return request; | ||
369 | *eof = 1; | ||
370 | return len - offset; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. | ||
375 | */ | ||
376 | static int drm_queues_info(char *buf, char **start, off_t offset, int request, | ||
377 | int *eof, void *data) | ||
378 | { | ||
379 | struct drm_minor *minor = (struct drm_minor *) data; | ||
380 | struct drm_device *dev = minor->dev; | ||
381 | int ret; | ||
382 | |||
383 | mutex_lock(&dev->struct_mutex); | ||
384 | ret = drm__queues_info(buf, start, offset, request, eof, data); | ||
385 | mutex_unlock(&dev->struct_mutex); | ||
386 | return ret; | ||
387 | } | 180 | } |
388 | 181 | ||
389 | /** | 182 | int drm_proc_remove_files(struct drm_info_list *files, int count, |
390 | * Called when "/proc/dri/.../bufs" is read. | 183 | struct drm_minor *minor) |
391 | * | ||
392 | * \param buf output buffer. | ||
393 | * \param start start of output data. | ||
394 | * \param offset requested start offset. | ||
395 | * \param request requested number of bytes. | ||
396 | * \param eof whether there is no more data to return. | ||
397 | * \param data private data. | ||
398 | * \return number of written bytes. | ||
399 | */ | ||
400 | static int drm__bufs_info(char *buf, char **start, off_t offset, int request, | ||
401 | int *eof, void *data) | ||
402 | { | 184 | { |
403 | struct drm_minor *minor = (struct drm_minor *) data; | 185 | struct list_head *pos, *q; |
404 | struct drm_device *dev = minor->dev; | 186 | struct drm_info_node *tmp; |
405 | int len = 0; | ||
406 | struct drm_device_dma *dma = dev->dma; | ||
407 | int i; | 187 | int i; |
408 | 188 | ||
409 | if (!dma || offset > DRM_PROC_LIMIT) { | 189 | for (i = 0; i < count; i++) { |
410 | *eof = 1; | 190 | list_for_each_safe(pos, q, &minor->proc_nodes.list) { |
411 | return 0; | 191 | tmp = list_entry(pos, struct drm_info_node, list); |
412 | } | 192 | if (tmp->info_ent == &files[i]) { |
413 | 193 | remove_proc_entry(files[i].name, | |
414 | *start = &buf[offset]; | 194 | minor->proc_root); |
415 | *eof = 0; | 195 | list_del(pos); |
416 | 196 | drm_free(tmp, sizeof(struct drm_info_node), | |
417 | DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); | 197 | _DRM_DRIVER); |
418 | for (i = 0; i <= DRM_MAX_ORDER; i++) { | 198 | } |
419 | if (dma->bufs[i].buf_count) | 199 | } |
420 | DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", | ||
421 | i, | ||
422 | dma->bufs[i].buf_size, | ||
423 | dma->bufs[i].buf_count, | ||
424 | atomic_read(&dma->bufs[i] | ||
425 | .freelist.count), | ||
426 | dma->bufs[i].seg_count, | ||
427 | dma->bufs[i].seg_count | ||
428 | * (1 << dma->bufs[i].page_order), | ||
429 | (dma->bufs[i].seg_count | ||
430 | * (1 << dma->bufs[i].page_order)) | ||
431 | * PAGE_SIZE / 1024); | ||
432 | } | ||
433 | DRM_PROC_PRINT("\n"); | ||
434 | for (i = 0; i < dma->buf_count; i++) { | ||
435 | if (i && !(i % 32)) | ||
436 | DRM_PROC_PRINT("\n"); | ||
437 | DRM_PROC_PRINT(" %d", dma->buflist[i]->list); | ||
438 | } | 200 | } |
439 | DRM_PROC_PRINT("\n"); | 201 | return 0; |
440 | |||
441 | if (len > request + offset) | ||
442 | return request; | ||
443 | *eof = 1; | ||
444 | return len - offset; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. | ||
449 | */ | ||
450 | static int drm_bufs_info(char *buf, char **start, off_t offset, int request, | ||
451 | int *eof, void *data) | ||
452 | { | ||
453 | struct drm_minor *minor = (struct drm_minor *) data; | ||
454 | struct drm_device *dev = minor->dev; | ||
455 | int ret; | ||
456 | |||
457 | mutex_lock(&dev->struct_mutex); | ||
458 | ret = drm__bufs_info(buf, start, offset, request, eof, data); | ||
459 | mutex_unlock(&dev->struct_mutex); | ||
460 | return ret; | ||
461 | } | 202 | } |
462 | 203 | ||
463 | /** | 204 | /** |
464 | * Called when "/proc/dri/.../vblank" is read. | 205 | * Cleanup the proc filesystem resources. |
465 | * | 206 | * |
466 | * \param buf output buffer. | 207 | * \param minor device minor number. |
467 | * \param start start of output data. | 208 | * \param root DRI proc dir entry. |
468 | * \param offset requested start offset. | 209 | * \param dev_root DRI device proc dir entry. |
469 | * \param request requested number of bytes. | 210 | * \return always zero. |
470 | * \param eof whether there is no more data to return. | ||
471 | * \param data private data. | ||
472 | * \return number of written bytes. | ||
473 | */ | ||
474 | static int drm__vblank_info(char *buf, char **start, off_t offset, int request, | ||
475 | int *eof, void *data) | ||
476 | { | ||
477 | struct drm_minor *minor = (struct drm_minor *) data; | ||
478 | struct drm_device *dev = minor->dev; | ||
479 | int len = 0; | ||
480 | int crtc; | ||
481 | |||
482 | if (offset > DRM_PROC_LIMIT) { | ||
483 | *eof = 1; | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | *start = &buf[offset]; | ||
488 | *eof = 0; | ||
489 | |||
490 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { | ||
491 | DRM_PROC_PRINT("CRTC %d enable: %d\n", | ||
492 | crtc, atomic_read(&dev->vblank_refcount[crtc])); | ||
493 | DRM_PROC_PRINT("CRTC %d counter: %d\n", | ||
494 | crtc, drm_vblank_count(dev, crtc)); | ||
495 | DRM_PROC_PRINT("CRTC %d last wait: %d\n", | ||
496 | crtc, dev->last_vblank_wait[crtc]); | ||
497 | DRM_PROC_PRINT("CRTC %d in modeset: %d\n", | ||
498 | crtc, dev->vblank_inmodeset[crtc]); | ||
499 | } | ||
500 | |||
501 | if (len > request + offset) | ||
502 | return request; | ||
503 | *eof = 1; | ||
504 | return len - offset; | ||
505 | } | ||
506 | |||
507 | /** | ||
508 | * Simply calls _vblank_info() while holding the drm_device::struct_mutex lock. | ||
509 | */ | ||
510 | static int drm_vblank_info(char *buf, char **start, off_t offset, int request, | ||
511 | int *eof, void *data) | ||
512 | { | ||
513 | struct drm_minor *minor = (struct drm_minor *) data; | ||
514 | struct drm_device *dev = minor->dev; | ||
515 | int ret; | ||
516 | |||
517 | mutex_lock(&dev->struct_mutex); | ||
518 | ret = drm__vblank_info(buf, start, offset, request, eof, data); | ||
519 | mutex_unlock(&dev->struct_mutex); | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | /** | ||
524 | * Called when "/proc/dri/.../clients" is read. | ||
525 | * | 211 | * |
526 | * \param buf output buffer. | 212 | * Remove all proc entries created by proc_init(). |
527 | * \param start start of output data. | ||
528 | * \param offset requested start offset. | ||
529 | * \param request requested number of bytes. | ||
530 | * \param eof whether there is no more data to return. | ||
531 | * \param data private data. | ||
532 | * \return number of written bytes. | ||
533 | */ | 213 | */ |
534 | static int drm__clients_info(char *buf, char **start, off_t offset, | 214 | int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) |
535 | int request, int *eof, void *data) | ||
536 | { | 215 | { |
537 | struct drm_minor *minor = (struct drm_minor *) data; | ||
538 | struct drm_device *dev = minor->dev; | 216 | struct drm_device *dev = minor->dev; |
539 | int len = 0; | 217 | char name[64]; |
540 | struct drm_file *priv; | ||
541 | 218 | ||
542 | if (offset > DRM_PROC_LIMIT) { | 219 | if (!root || !minor->proc_root) |
543 | *eof = 1; | ||
544 | return 0; | 220 | return 0; |
545 | } | ||
546 | |||
547 | *start = &buf[offset]; | ||
548 | *eof = 0; | ||
549 | |||
550 | DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); | ||
551 | list_for_each_entry(priv, &dev->filelist, lhead) { | ||
552 | DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", | ||
553 | priv->authenticated ? 'y' : 'n', | ||
554 | priv->minor->index, | ||
555 | priv->pid, | ||
556 | priv->uid, priv->magic, priv->ioctl_count); | ||
557 | } | ||
558 | 221 | ||
559 | if (len > request + offset) | 222 | if (dev->driver->proc_cleanup) |
560 | return request; | 223 | dev->driver->proc_cleanup(minor); |
561 | *eof = 1; | ||
562 | return len - offset; | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. | ||
567 | */ | ||
568 | static int drm_clients_info(char *buf, char **start, off_t offset, | ||
569 | int request, int *eof, void *data) | ||
570 | { | ||
571 | struct drm_minor *minor = (struct drm_minor *) data; | ||
572 | struct drm_device *dev = minor->dev; | ||
573 | int ret; | ||
574 | |||
575 | mutex_lock(&dev->struct_mutex); | ||
576 | ret = drm__clients_info(buf, start, offset, request, eof, data); | ||
577 | mutex_unlock(&dev->struct_mutex); | ||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | struct drm_gem_name_info_data { | ||
582 | int len; | ||
583 | char *buf; | ||
584 | int eof; | ||
585 | }; | ||
586 | 224 | ||
587 | static int drm_gem_one_name_info(int id, void *ptr, void *data) | 225 | drm_proc_remove_files(drm_proc_list, DRM_PROC_ENTRIES, minor); |
588 | { | ||
589 | struct drm_gem_object *obj = ptr; | ||
590 | struct drm_gem_name_info_data *nid = data; | ||
591 | 226 | ||
592 | DRM_INFO("name %d size %zd\n", obj->name, obj->size); | 227 | sprintf(name, "%d", minor->index); |
593 | if (nid->eof) | 228 | remove_proc_entry(name, root); |
594 | return 0; | ||
595 | 229 | ||
596 | nid->len += sprintf(&nid->buf[nid->len], | ||
597 | "%6d %8zd %7d %8d\n", | ||
598 | obj->name, obj->size, | ||
599 | atomic_read(&obj->handlecount.refcount), | ||
600 | atomic_read(&obj->refcount.refcount)); | ||
601 | if (nid->len > DRM_PROC_LIMIT) { | ||
602 | nid->eof = 1; | ||
603 | return 0; | ||
604 | } | ||
605 | return 0; | 230 | return 0; |
606 | } | 231 | } |
607 | 232 | ||
608 | static int drm_gem_name_info(char *buf, char **start, off_t offset, | ||
609 | int request, int *eof, void *data) | ||
610 | { | ||
611 | struct drm_minor *minor = (struct drm_minor *) data; | ||
612 | struct drm_device *dev = minor->dev; | ||
613 | struct drm_gem_name_info_data nid; | ||
614 | |||
615 | if (offset > DRM_PROC_LIMIT) { | ||
616 | *eof = 1; | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | nid.len = sprintf(buf, " name size handles refcount\n"); | ||
621 | nid.buf = buf; | ||
622 | nid.eof = 0; | ||
623 | idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid); | ||
624 | |||
625 | *start = &buf[offset]; | ||
626 | *eof = 0; | ||
627 | if (nid.len > request + offset) | ||
628 | return request; | ||
629 | *eof = 1; | ||
630 | return nid.len - offset; | ||
631 | } | ||
632 | |||
633 | static int drm_gem_object_info(char *buf, char **start, off_t offset, | ||
634 | int request, int *eof, void *data) | ||
635 | { | ||
636 | struct drm_minor *minor = (struct drm_minor *) data; | ||
637 | struct drm_device *dev = minor->dev; | ||
638 | int len = 0; | ||
639 | |||
640 | if (offset > DRM_PROC_LIMIT) { | ||
641 | *eof = 1; | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | *start = &buf[offset]; | ||
646 | *eof = 0; | ||
647 | DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count)); | ||
648 | DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory)); | ||
649 | DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count)); | ||
650 | DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory)); | ||
651 | DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory)); | ||
652 | DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total); | ||
653 | if (len > request + offset) | ||
654 | return request; | ||
655 | *eof = 1; | ||
656 | return len - offset; | ||
657 | } | ||
658 | |||
659 | #if DRM_DEBUG_CODE | ||
660 | |||
661 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, | ||
662 | int *eof, void *data) | ||
663 | { | ||
664 | struct drm_minor *minor = (struct drm_minor *) data; | ||
665 | struct drm_device *dev = minor->dev; | ||
666 | int len = 0; | ||
667 | struct drm_vma_entry *pt; | ||
668 | struct vm_area_struct *vma; | ||
669 | #if defined(__i386__) | ||
670 | unsigned int pgprot; | ||
671 | #endif | ||
672 | |||
673 | if (offset > DRM_PROC_LIMIT) { | ||
674 | *eof = 1; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | *start = &buf[offset]; | ||
679 | *eof = 0; | ||
680 | |||
681 | DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%llx\n", | ||
682 | atomic_read(&dev->vma_count), | ||
683 | high_memory, (u64)virt_to_phys(high_memory)); | ||
684 | list_for_each_entry(pt, &dev->vmalist, head) { | ||
685 | if (!(vma = pt->vma)) | ||
686 | continue; | ||
687 | DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", | ||
688 | pt->pid, | ||
689 | vma->vm_start, | ||
690 | vma->vm_end, | ||
691 | vma->vm_flags & VM_READ ? 'r' : '-', | ||
692 | vma->vm_flags & VM_WRITE ? 'w' : '-', | ||
693 | vma->vm_flags & VM_EXEC ? 'x' : '-', | ||
694 | vma->vm_flags & VM_MAYSHARE ? 's' : 'p', | ||
695 | vma->vm_flags & VM_LOCKED ? 'l' : '-', | ||
696 | vma->vm_flags & VM_IO ? 'i' : '-', | ||
697 | vma->vm_pgoff); | ||
698 | |||
699 | #if defined(__i386__) | ||
700 | pgprot = pgprot_val(vma->vm_page_prot); | ||
701 | DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", | ||
702 | pgprot & _PAGE_PRESENT ? 'p' : '-', | ||
703 | pgprot & _PAGE_RW ? 'w' : 'r', | ||
704 | pgprot & _PAGE_USER ? 'u' : 's', | ||
705 | pgprot & _PAGE_PWT ? 't' : 'b', | ||
706 | pgprot & _PAGE_PCD ? 'u' : 'c', | ||
707 | pgprot & _PAGE_ACCESSED ? 'a' : '-', | ||
708 | pgprot & _PAGE_DIRTY ? 'd' : '-', | ||
709 | pgprot & _PAGE_PSE ? 'm' : 'k', | ||
710 | pgprot & _PAGE_GLOBAL ? 'g' : 'l'); | ||
711 | #endif | ||
712 | DRM_PROC_PRINT("\n"); | ||
713 | } | ||
714 | |||
715 | if (len > request + offset) | ||
716 | return request; | ||
717 | *eof = 1; | ||
718 | return len - offset; | ||
719 | } | ||
720 | |||
721 | static int drm_vma_info(char *buf, char **start, off_t offset, int request, | ||
722 | int *eof, void *data) | ||
723 | { | ||
724 | struct drm_minor *minor = (struct drm_minor *) data; | ||
725 | struct drm_device *dev = minor->dev; | ||
726 | int ret; | ||
727 | |||
728 | mutex_lock(&dev->struct_mutex); | ||
729 | ret = drm__vma_info(buf, start, offset, request, eof, data); | ||
730 | mutex_unlock(&dev->struct_mutex); | ||
731 | return ret; | ||
732 | } | ||
733 | #endif | ||