drm: Implement and use Linux struct device
[dragonfly.git] / sys / dev / drm / drm_sysctl.c
blob98ee3472185e50744611dfa282b30a2c3e270aae
1 /*-
2 * Copyright 2003 Eric Anholt
3 * All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * $FreeBSD: src/sys/dev/drm2/drm_sysctl.c,v 1.1 2012/05/22 11:07:44 kib Exp $
26 /** @file drm_sysctl.c
27 * Implementation of various sysctls for controlling DRM behavior and reporting
28 * debug information.
31 #include <sys/conf.h>
32 #include <sys/sysctl.h>
33 #include <sys/types.h>
35 #include <drm/drmP.h>
36 #include "drm_legacy.h"
38 SYSCTL_NODE(_hw, OID_AUTO, dri, CTLFLAG_RD, 0, "DRI Graphics");
39 SYSCTL_INT(_hw_dri, OID_AUTO, debug, CTLFLAG_RW, &drm_debug, 0,
40 "Enable debugging output");
41 SYSCTL_INT(_hw_dri, OID_AUTO, vblank_offdelay, CTLFLAG_RW,
42 &drm_vblank_offdelay, 0, "Delay until vblank irq auto-disable");
43 SYSCTL_INT(_hw_dri, OID_AUTO, timestamp_precision, CTLFLAG_RW,
44 &drm_timestamp_precision, 0, "Max. error on timestamps");
46 static int drm_name_info DRM_SYSCTL_HANDLER_ARGS;
47 static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
48 static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
49 static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
51 struct drm_sysctl_list {
52 const char *name;
53 int (*f) DRM_SYSCTL_HANDLER_ARGS;
54 } drm_sysctl_list[] = {
55 {"name", drm_name_info},
56 {"vm", drm_vm_info},
57 {"clients", drm_clients_info},
58 {"bufs", drm_bufs_info},
60 #define DRM_SYSCTL_ENTRIES NELEM(drm_sysctl_list)
62 int drm_sysctl_init(struct drm_device *dev)
64 struct drm_sysctl_info *info;
65 struct sysctl_oid *oid;
66 struct sysctl_oid *top;
67 int i, unit;
69 info = kzalloc(sizeof *info, GFP_KERNEL);
70 if ( !info )
71 return 1;
72 dev->sysctl = info;
74 unit = device_get_unit(dev->dev->bsddev);
75 if (unit > 9)
76 return 1;
78 /* Add the hw.dri.x for our device */
79 info->name[0] = '0' + unit;
80 info->name[1] = 0;
81 top = SYSCTL_ADD_NODE(&info->ctx, &SYSCTL_NODE_CHILDREN(_hw, dri),
82 OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
83 if (!top)
84 return 1;
86 for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
87 oid = SYSCTL_ADD_OID(&info->ctx,
88 SYSCTL_CHILDREN(top),
89 OID_AUTO,
90 drm_sysctl_list[i].name,
91 CTLTYPE_STRING | CTLFLAG_RD,
92 dev,
94 drm_sysctl_list[i].f,
95 "A",
96 NULL);
97 if (!oid)
98 return 1;
100 if (dev->driver->sysctl_init != NULL)
101 dev->driver->sysctl_init(dev, &info->ctx, top);
103 return (0);
106 int drm_sysctl_cleanup(struct drm_device *dev)
108 int error;
110 error = sysctl_ctx_free(&dev->sysctl->ctx);
111 kfree(dev->sysctl);
112 dev->sysctl = NULL;
113 if (dev->driver->sysctl_cleanup != NULL)
114 dev->driver->sysctl_cleanup(dev);
116 return (error);
119 #define DRM_SYSCTL_PRINT(fmt, arg...) \
120 do { \
121 ksnprintf(buf, sizeof(buf), fmt, ##arg); \
122 retcode = SYSCTL_OUT(req, buf, strlen(buf)); \
123 if (retcode) \
124 goto done; \
125 } while (0)
127 static int drm_name_info DRM_SYSCTL_HANDLER_ARGS
129 struct drm_device *dev = arg1;
130 char buf[128];
131 int retcode;
132 int hasunique = 0;
134 DRM_SYSCTL_PRINT("%s 0x%x", dev->driver->name, dev2udev(dev->devnode));
136 DRM_LOCK(dev);
137 if (dev->unique) {
138 ksnprintf(buf, sizeof(buf), " %s", dev->unique);
139 hasunique = 1;
141 DRM_UNLOCK(dev);
143 if (hasunique)
144 SYSCTL_OUT(req, buf, strlen(buf));
146 SYSCTL_OUT(req, "", 1);
148 done:
149 return retcode;
153 * Called when "/proc/dri/.../vm" is read.
155 * Prints information about all mappings in drm_device::maplist.
157 static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
159 char buf[128];
160 int retcode;
161 struct drm_device *dev = arg1;
162 struct drm_local_map *map;
163 struct drm_map_list *r_list;
165 /* Hardcoded from _DRM_FRAME_BUFFER,
166 _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
167 _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
168 const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
169 const char *type;
170 int i;
172 DRM_LOCK(dev);
173 DRM_SYSCTL_PRINT("\nslot offset size "
174 "type flags address handle mtrr\n");
175 i = 0;
176 list_for_each_entry(r_list, &dev->maplist, head) {
177 map = r_list->map;
178 if (!map)
179 continue;
180 if (map->type < 0 || map->type > 5)
181 type = "??";
182 else
183 type = types[map->type];
185 DRM_SYSCTL_PRINT("%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ",
187 (unsigned long long)map->offset,
188 map->size, type, map->flags,
189 (unsigned long) r_list->user_token);
190 if (map->mtrr < 0)
191 DRM_SYSCTL_PRINT("none\n");
192 else
193 DRM_SYSCTL_PRINT("%4d\n", map->mtrr);
194 i++;
197 SYSCTL_OUT(req, "", 1);
198 DRM_UNLOCK(dev);
200 done:
201 return 0;
204 static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
206 struct drm_device *dev = arg1;
207 struct drm_device_dma *dma = dev->dma;
208 struct drm_device_dma tempdma;
209 int *templists;
210 int i;
211 char buf[128];
212 int retcode;
214 /* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
215 * copy of the whole structure and the relevant data from buflist.
217 DRM_LOCK(dev);
218 if (dma == NULL) {
219 DRM_UNLOCK(dev);
220 return 0;
222 spin_lock(&dev->dma_lock);
223 tempdma = *dma;
224 templists = kmalloc(sizeof(int) * dma->buf_count, M_DRM,
225 M_WAITOK | M_NULLOK);
226 for (i = 0; i < dma->buf_count; i++)
227 templists[i] = dma->buflist[i]->list;
228 dma = &tempdma;
229 spin_unlock(&dev->dma_lock);
230 DRM_UNLOCK(dev);
232 DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n");
233 for (i = 0; i <= DRM_MAX_ORDER; i++) {
234 if (dma->bufs[i].buf_count)
235 DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d\n",
237 dma->bufs[i].buf_size,
238 dma->bufs[i].buf_count,
239 dma->bufs[i].seg_count,
240 dma->bufs[i].seg_count
241 *(1 << dma->bufs[i].page_order),
242 (dma->bufs[i].seg_count
243 * (1 << dma->bufs[i].page_order))
244 * (int)PAGE_SIZE / 1024);
246 DRM_SYSCTL_PRINT("\n");
247 for (i = 0; i < dma->buf_count; i++) {
248 if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
249 DRM_SYSCTL_PRINT(" %d", templists[i]);
251 DRM_SYSCTL_PRINT("\n");
253 SYSCTL_OUT(req, "", 1);
254 done:
255 kfree(templists);
256 return retcode;
259 static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
261 struct drm_device *dev = arg1;
262 struct drm_file *priv, *tempprivs;
263 char buf[128];
264 int retcode;
265 int privcount, i;
267 DRM_LOCK(dev);
269 privcount = 0;
270 list_for_each_entry(priv, &dev->filelist, lhead)
271 privcount++;
273 tempprivs = kmalloc(sizeof(struct drm_file) * privcount, M_DRM,
274 M_WAITOK | M_NULLOK);
275 if (tempprivs == NULL) {
276 DRM_UNLOCK(dev);
277 return ENOMEM;
279 i = 0;
280 list_for_each_entry(priv, &dev->filelist, lhead)
281 tempprivs[i++] = *priv;
283 DRM_UNLOCK(dev);
285 DRM_SYSCTL_PRINT(
286 "\na dev pid uid magic ioctls\n");
287 for (i = 0; i < privcount; i++) {
288 priv = &tempprivs[i];
289 DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n",
290 priv->authenticated ? 'y' : 'n',
291 devtoname(priv->dev->devnode),
292 priv->pid,
293 priv->uid,
294 priv->magic,
295 priv->ioctl_count);
298 SYSCTL_OUT(req, "", 1);
299 done:
300 kfree(tempprivs);
301 return retcode;