drm: Sync vblank handling code with Linux 3.14
[dragonfly.git] / sys / dev / drm / drm_sysctl.c
CommitLineData
7f3c3d6f
HT
1/*-
2 * Copyright 2003 Eric Anholt
3 * All Rights Reserved.
4 *
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:
11 *
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.
15 *
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.
5718399f
FT
22 *
23 * $FreeBSD: src/sys/dev/drm2/drm_sysctl.c,v 1.1 2012/05/22 11:07:44 kib Exp $
7f3c3d6f
HT
24 */
25
26/** @file drm_sysctl.c
27 * Implementation of various sysctls for controlling DRM behavior and reporting
28 * debug information.
29 */
30
5718399f
FT
31#include <sys/conf.h>
32#include <sys/sysctl.h>
33#include <sys/types.h>
34
18e26a6d 35#include <drm/drmP.h>
7f3c3d6f 36
7f3c3d6f
HT
37static int drm_name_info DRM_SYSCTL_HANDLER_ARGS;
38static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
39static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
40static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
41
42struct drm_sysctl_list {
43 const char *name;
44 int (*f) DRM_SYSCTL_HANDLER_ARGS;
45} drm_sysctl_list[] = {
46 {"name", drm_name_info},
47 {"vm", drm_vm_info},
48 {"clients", drm_clients_info},
49 {"bufs", drm_bufs_info},
50};
c157ff7a 51#define DRM_SYSCTL_ENTRIES NELEM(drm_sysctl_list)
7f3c3d6f 52
b3705d71 53int drm_sysctl_init(struct drm_device *dev)
7f3c3d6f
HT
54{
55 struct drm_sysctl_info *info;
56 struct sysctl_oid *oid;
57 struct sysctl_oid *top, *drioid;
58 int i;
59
5a3b77d5 60 info = kmalloc(sizeof *info, M_DRM, M_WAITOK | M_ZERO);
7f3c3d6f
HT
61 if ( !info )
62 return 1;
63 dev->sysctl = info;
64
65 /* Add the sysctl node for DRI if it doesn't already exist */
5718399f
FT
66 drioid = SYSCTL_ADD_NODE(&info->ctx, &sysctl__hw_children, OID_AUTO,
67 "dri", CTLFLAG_RW, NULL, "DRI Graphics");
7f3c3d6f
HT
68 if (!drioid)
69 return 1;
70
71 /* Find the next free slot under hw.dri */
72 i = 0;
73 SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) {
74 if (i <= oid->oid_arg2)
75 i = oid->oid_arg2 + 1;
76 }
77 if (i>9)
78 return 1;
79
5718399f 80 dev->sysctl_node_idx = i;
7f3c3d6f
HT
81 /* Add the hw.dri.x for our device */
82 info->name[0] = '0' + i;
83 info->name[1] = 0;
5718399f
FT
84 top = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(drioid),
85 OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
7f3c3d6f
HT
86 if (!top)
87 return 1;
88
89 for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
5718399f
FT
90 oid = SYSCTL_ADD_OID(&info->ctx,
91 SYSCTL_CHILDREN(top),
92 OID_AUTO,
93 drm_sysctl_list[i].name,
94 CTLTYPE_STRING | CTLFLAG_RD,
95 dev,
96 0,
97 drm_sysctl_list[i].f,
98 "A",
7f3c3d6f
HT
99 NULL);
100 if (!oid)
101 return 1;
102 }
5718399f 103 SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "debug",
1d5dd71d 104 CTLFLAG_RW, &drm_debug, sizeof(drm_debug),
7f3c3d6f 105 "Enable debugging output");
5718399f 106 SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "notyet",
1d5dd71d 107 CTLFLAG_RW, &drm_notyet_flag, sizeof(drm_debug),
5718399f
FT
108 "Enable notyet reminders");
109
110 if (dev->driver->sysctl_init != NULL)
111 dev->driver->sysctl_init(dev, &info->ctx, top);
112
113 SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
114 "vblank_offdelay", CTLFLAG_RW, &drm_vblank_offdelay,
115 sizeof(drm_vblank_offdelay),
116 "");
117 SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
118 "timestamp_precision", CTLFLAG_RW, &drm_timestamp_precision,
119 sizeof(drm_timestamp_precision),
120 "");
121
122 return (0);
7f3c3d6f
HT
123}
124
b3705d71 125int drm_sysctl_cleanup(struct drm_device *dev)
7f3c3d6f
HT
126{
127 int error;
7f3c3d6f 128
5718399f 129 error = sysctl_ctx_free(&dev->sysctl->ctx);
5a3b77d5 130 drm_free(dev->sysctl, M_DRM);
7f3c3d6f 131 dev->sysctl = NULL;
5718399f
FT
132 if (dev->driver->sysctl_cleanup != NULL)
133 dev->driver->sysctl_cleanup(dev);
7f3c3d6f 134
5718399f 135 return (error);
7f3c3d6f
HT
136}
137
138#define DRM_SYSCTL_PRINT(fmt, arg...) \
139do { \
5718399f 140 ksnprintf(buf, sizeof(buf), fmt, ##arg); \
7f3c3d6f
HT
141 retcode = SYSCTL_OUT(req, buf, strlen(buf)); \
142 if (retcode) \
143 goto done; \
144} while (0)
145
146static int drm_name_info DRM_SYSCTL_HANDLER_ARGS
147{
b3705d71 148 struct drm_device *dev = arg1;
7f3c3d6f
HT
149 char buf[128];
150 int retcode;
151 int hasunique = 0;
152
b3705d71 153 DRM_SYSCTL_PRINT("%s 0x%x", dev->driver->name, dev2udev(dev->devnode));
7f3c3d6f 154
5718399f 155 DRM_LOCK(dev);
7f3c3d6f 156 if (dev->unique) {
5718399f 157 ksnprintf(buf, sizeof(buf), " %s", dev->unique);
7f3c3d6f
HT
158 hasunique = 1;
159 }
5718399f 160 DRM_UNLOCK(dev);
7f3c3d6f
HT
161
162 if (hasunique)
163 SYSCTL_OUT(req, buf, strlen(buf));
164
165 SYSCTL_OUT(req, "", 1);
166
167done:
168 return retcode;
169}
170
f599cd46
FT
171/**
172 * Called when "/proc/dri/.../vm" is read.
173 *
174 * Prints information about all mappings in drm_device::maplist.
175 */
7f3c3d6f
HT
176static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
177{
7f3c3d6f
HT
178 char buf[128];
179 int retcode;
f599cd46
FT
180 struct drm_device *dev = arg1;
181 struct drm_local_map *map;
182 struct drm_map_list *r_list;
7f3c3d6f 183
f599cd46
FT
184 /* Hardcoded from _DRM_FRAME_BUFFER,
185 _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
186 _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
187 const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
188 const char *type;
189 int i;
7f3c3d6f 190
f599cd46 191 DRM_LOCK(dev);
b3705d71 192 DRM_SYSCTL_PRINT("\nslot offset size "
99f70504 193 "type flags address handle mtrr\n");
f599cd46
FT
194 i = 0;
195 list_for_each_entry(r_list, &dev->maplist, head) {
196 map = r_list->map;
197 if (!map)
198 continue;
199 if (map->type < 0 || map->type > 5)
7f3c3d6f 200 type = "??";
f599cd46 201 else
7f3c3d6f
HT
202 type = types[map->type];
203
f599cd46
FT
204 DRM_SYSCTL_PRINT("%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ",
205 i,
206 (unsigned long long)map->offset,
207 map->size, type, map->flags,
208 (unsigned long) r_list->user_token);
209 if (map->mtrr < 0)
210 DRM_SYSCTL_PRINT("none\n");
7f3c3d6f 211 else
f599cd46
FT
212 DRM_SYSCTL_PRINT("%4d\n", map->mtrr);
213 i++;
7f3c3d6f 214
7f3c3d6f
HT
215 }
216 SYSCTL_OUT(req, "", 1);
f599cd46 217 DRM_UNLOCK(dev);
7f3c3d6f
HT
218
219done:
f599cd46 220 return 0;
7f3c3d6f
HT
221}
222
223static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
224{
b3705d71 225 struct drm_device *dev = arg1;
7f3c3d6f
HT
226 drm_device_dma_t *dma = dev->dma;
227 drm_device_dma_t tempdma;
228 int *templists;
229 int i;
230 char buf[128];
231 int retcode;
232
233 /* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
234 * copy of the whole structure and the relevant data from buflist.
235 */
5718399f 236 DRM_LOCK(dev);
7f3c3d6f 237 if (dma == NULL) {
5718399f 238 DRM_UNLOCK(dev);
7f3c3d6f
HT
239 return 0;
240 }
5718399f 241 spin_lock(&dev->dma_lock);
7f3c3d6f 242 tempdma = *dma;
5a3b77d5 243 templists = kmalloc(sizeof(int) * dma->buf_count, M_DRM,
f8677ba6 244 M_WAITOK | M_NULLOK);
7f3c3d6f
HT
245 for (i = 0; i < dma->buf_count; i++)
246 templists[i] = dma->buflist[i]->list;
247 dma = &tempdma;
5718399f
FT
248 spin_unlock(&dev->dma_lock);
249 DRM_UNLOCK(dev);
7f3c3d6f
HT
250
251 DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n");
252 for (i = 0; i <= DRM_MAX_ORDER; i++) {
253 if (dma->bufs[i].buf_count)
254 DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
255 i,
256 dma->bufs[i].buf_size,
257 dma->bufs[i].buf_count,
258 atomic_read(&dma->bufs[i]
259 .freelist.count),
260 dma->bufs[i].seg_count,
261 dma->bufs[i].seg_count
262 *(1 << dma->bufs[i].page_order),
263 (dma->bufs[i].seg_count
264 * (1 << dma->bufs[i].page_order))
5718399f 265 * (int)PAGE_SIZE / 1024);
7f3c3d6f
HT
266 }
267 DRM_SYSCTL_PRINT("\n");
268 for (i = 0; i < dma->buf_count; i++) {
269 if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
270 DRM_SYSCTL_PRINT(" %d", templists[i]);
271 }
272 DRM_SYSCTL_PRINT("\n");
273
274 SYSCTL_OUT(req, "", 1);
275done:
5a3b77d5 276 drm_free(templists, M_DRM);
7f3c3d6f
HT
277 return retcode;
278}
279
280static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
281{
b3705d71
HT
282 struct drm_device *dev = arg1;
283 struct drm_file *priv, *tempprivs;
7f3c3d6f
HT
284 char buf[128];
285 int retcode;
286 int privcount, i;
287
5718399f 288 DRM_LOCK(dev);
7f3c3d6f
HT
289
290 privcount = 0;
1610a1a0 291 list_for_each_entry(priv, &dev->filelist, lhead)
7f3c3d6f
HT
292 privcount++;
293
5a3b77d5 294 tempprivs = kmalloc(sizeof(struct drm_file) * privcount, M_DRM,
f8677ba6 295 M_WAITOK | M_NULLOK);
7f3c3d6f 296 if (tempprivs == NULL) {
5718399f 297 DRM_UNLOCK(dev);
7f3c3d6f
HT
298 return ENOMEM;
299 }
300 i = 0;
1610a1a0 301 list_for_each_entry(priv, &dev->filelist, lhead)
7f3c3d6f
HT
302 tempprivs[i++] = *priv;
303
5718399f 304 DRM_UNLOCK(dev);
7f3c3d6f 305
5718399f
FT
306 DRM_SYSCTL_PRINT(
307 "\na dev pid uid magic ioctls\n");
7f3c3d6f
HT
308 for (i = 0; i < privcount; i++) {
309 priv = &tempprivs[i];
5718399f 310 DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n",
7f3c3d6f 311 priv->authenticated ? 'y' : 'n',
79f713b0 312 devtoname(priv->dev->devnode),
7f3c3d6f
HT
313 priv->pid,
314 priv->uid,
315 priv->magic,
316 priv->ioctl_count);
317 }
318
319 SYSCTL_OUT(req, "", 1);
320done:
5a3b77d5 321 drm_free(tempprivs, M_DRM);
7f3c3d6f
HT
322 return retcode;
323}