drm_sysctl.c revision 267992
1235783Skib/*-
2235783Skib * Copyright 2003 Eric Anholt
3235783Skib * All Rights Reserved.
4235783Skib *
5235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
6235783Skib * copy of this software and associated documentation files (the "Software"),
7235783Skib * to deal in the Software without restriction, including without limitation
8235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9235783Skib * and/or sell copies of the Software, and to permit persons to whom the
10235783Skib * Software is furnished to do so, subject to the following conditions:
11235783Skib *
12235783Skib * The above copyright notice and this permission notice (including the next
13235783Skib * paragraph) shall be included in all copies or substantial portions of the
14235783Skib * Software.
15235783Skib *
16235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19235783Skib * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20235783Skib * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21235783Skib * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22235783Skib */
23235783Skib
24235783Skib#include <sys/cdefs.h>
25235783Skib__FBSDID("$FreeBSD: head/sys/dev/drm2/drm_sysctl.c 267992 2014-06-28 03:56:17Z hselasky $");
26235783Skib
27235783Skib/** @file drm_sysctl.c
28235783Skib * Implementation of various sysctls for controlling DRM behavior and reporting
29235783Skib * debug information.
30235783Skib */
31235783Skib
32235783Skib#include <dev/drm2/drmP.h>
33235783Skib#include <dev/drm2/drm.h>
34235783Skib
35235783Skib#include <sys/sysctl.h>
36235783Skib
37235783Skibstatic int	   drm_name_info DRM_SYSCTL_HANDLER_ARGS;
38235783Skibstatic int	   drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
39235783Skibstatic int	   drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
40235783Skibstatic int	   drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
41235783Skibstatic int	   drm_vblank_info DRM_SYSCTL_HANDLER_ARGS;
42235783Skib
43235783Skibstruct drm_sysctl_list {
44235783Skib	const char *name;
45235783Skib	int	   (*f) DRM_SYSCTL_HANDLER_ARGS;
46235783Skib} drm_sysctl_list[] = {
47235783Skib	{"name",    drm_name_info},
48235783Skib	{"vm",	    drm_vm_info},
49235783Skib	{"clients", drm_clients_info},
50235783Skib	{"bufs",    drm_bufs_info},
51235783Skib	{"vblank",    drm_vblank_info},
52235783Skib};
53235783Skib#define DRM_SYSCTL_ENTRIES (sizeof(drm_sysctl_list)/sizeof(drm_sysctl_list[0]))
54235783Skib
55235783Skibstruct drm_sysctl_info {
56235783Skib	struct sysctl_ctx_list ctx;
57235783Skib	char		       name[2];
58235783Skib};
59235783Skib
60235783Skibint drm_sysctl_init(struct drm_device *dev)
61235783Skib{
62235783Skib	struct drm_sysctl_info *info;
63235783Skib	struct sysctl_oid *oid;
64235783Skib	struct sysctl_oid *top, *drioid;
65235783Skib	int		  i;
66235783Skib
67235783Skib	info = malloc(sizeof *info, DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
68235783Skib	dev->sysctl = info;
69235783Skib
70235783Skib	/* Add the sysctl node for DRI if it doesn't already exist */
71267992Shselasky	drioid = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(&sysctl___hw), OID_AUTO,
72235783Skib	    "dri", CTLFLAG_RW, NULL, "DRI Graphics");
73235783Skib	if (!drioid)
74235783Skib		return 1;
75235783Skib
76235783Skib	/* Find the next free slot under hw.dri */
77235783Skib	i = 0;
78235783Skib	SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) {
79235783Skib		if (i <= oid->oid_arg2)
80235783Skib			i = oid->oid_arg2 + 1;
81235783Skib	}
82235783Skib	if (i > 9)
83235783Skib		return (1);
84235783Skib
85235783Skib	dev->sysctl_node_idx = i;
86235783Skib	/* Add the hw.dri.x for our device */
87235783Skib	info->name[0] = '0' + i;
88235783Skib	info->name[1] = 0;
89235783Skib	top = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(drioid),
90235783Skib	    OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
91235783Skib	if (!top)
92235783Skib		return 1;
93235783Skib
94235783Skib	for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
95235783Skib		oid = SYSCTL_ADD_OID(&info->ctx,
96235783Skib			SYSCTL_CHILDREN(top),
97235783Skib			OID_AUTO,
98235783Skib			drm_sysctl_list[i].name,
99235783Skib			CTLTYPE_STRING | CTLFLAG_RD,
100235783Skib			dev,
101235783Skib			0,
102235783Skib			drm_sysctl_list[i].f,
103235783Skib			"A",
104235783Skib			NULL);
105235783Skib		if (!oid)
106235783Skib			return 1;
107235783Skib	}
108235783Skib	SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "debug",
109235783Skib	    CTLFLAG_RW, &drm_debug_flag, sizeof(drm_debug_flag),
110235783Skib	    "Enable debugging output");
111235783Skib	SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "notyet",
112235783Skib	    CTLFLAG_RW, &drm_notyet_flag, sizeof(drm_debug_flag),
113235783Skib	    "Enable notyet reminders");
114235783Skib
115235783Skib	if (dev->driver->sysctl_init != NULL)
116235783Skib		dev->driver->sysctl_init(dev, &info->ctx, top);
117235783Skib
118235783Skib	SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
119235783Skib	    "vblank_offdelay", CTLFLAG_RW, &drm_vblank_offdelay,
120235783Skib	    sizeof(drm_vblank_offdelay),
121235783Skib	    "");
122235783Skib	SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
123235783Skib	    "timestamp_precision", CTLFLAG_RW, &drm_timestamp_precision,
124235783Skib	    sizeof(drm_timestamp_precision),
125235783Skib	    "");
126235783Skib
127235783Skib	return (0);
128235783Skib}
129235783Skib
130235783Skibint drm_sysctl_cleanup(struct drm_device *dev)
131235783Skib{
132235783Skib	int error;
133235783Skib
134235783Skib	error = sysctl_ctx_free(&dev->sysctl->ctx);
135235783Skib	free(dev->sysctl, DRM_MEM_DRIVER);
136235783Skib	dev->sysctl = NULL;
137235783Skib	if (dev->driver->sysctl_cleanup != NULL)
138235783Skib		dev->driver->sysctl_cleanup(dev);
139235783Skib
140235783Skib	return (error);
141235783Skib}
142235783Skib
143235783Skib#define DRM_SYSCTL_PRINT(fmt, arg...)				\
144235783Skibdo {								\
145235783Skib	snprintf(buf, sizeof(buf), fmt, ##arg);			\
146235783Skib	retcode = SYSCTL_OUT(req, buf, strlen(buf));		\
147235783Skib	if (retcode)						\
148235783Skib		goto done;					\
149235783Skib} while (0)
150235783Skib
151235783Skibstatic int drm_name_info DRM_SYSCTL_HANDLER_ARGS
152235783Skib{
153235783Skib	struct drm_device *dev = arg1;
154235783Skib	char buf[128];
155235783Skib	int retcode;
156235783Skib	int hasunique = 0;
157235783Skib
158235783Skib	DRM_SYSCTL_PRINT("%s 0x%x", dev->driver->name, dev2udev(dev->devnode));
159235783Skib
160235783Skib	DRM_LOCK(dev);
161235783Skib	if (dev->unique) {
162235783Skib		snprintf(buf, sizeof(buf), " %s", dev->unique);
163235783Skib		hasunique = 1;
164235783Skib	}
165235783Skib	DRM_UNLOCK(dev);
166235783Skib
167235783Skib	if (hasunique)
168235783Skib		SYSCTL_OUT(req, buf, strlen(buf));
169235783Skib
170235783Skib	SYSCTL_OUT(req, "", 1);
171235783Skib
172235783Skibdone:
173235783Skib	return retcode;
174235783Skib}
175235783Skib
176235783Skibstatic int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
177235783Skib{
178235783Skib	struct drm_device *dev = arg1;
179235783Skib	drm_local_map_t *map, *tempmaps;
180255012Sjkim	const char *types[] = {
181255012Sjkim		[_DRM_FRAME_BUFFER] = "FB",
182255012Sjkim		[_DRM_REGISTERS] = "REG",
183255012Sjkim		[_DRM_SHM] = "SHM",
184255012Sjkim		[_DRM_AGP] = "AGP",
185255012Sjkim		[_DRM_SCATTER_GATHER] = "SG",
186255012Sjkim		[_DRM_CONSISTENT] = "CONS",
187255012Sjkim		[_DRM_GEM] = "GEM"
188255012Sjkim	};
189235783Skib	const char *type, *yesno;
190235783Skib	int i, mapcount;
191235783Skib	char buf[128];
192235783Skib	int retcode;
193235783Skib
194235783Skib	/* We can't hold the lock while doing SYSCTL_OUTs, so allocate a
195235783Skib	 * temporary copy of all the map entries and then SYSCTL_OUT that.
196235783Skib	 */
197235783Skib	DRM_LOCK(dev);
198235783Skib
199235783Skib	mapcount = 0;
200235783Skib	TAILQ_FOREACH(map, &dev->maplist, link)
201235783Skib		mapcount++;
202235783Skib
203235783Skib	tempmaps = malloc(sizeof(drm_local_map_t) * mapcount, DRM_MEM_DRIVER,
204235783Skib	    M_NOWAIT);
205235783Skib	if (tempmaps == NULL) {
206235783Skib		DRM_UNLOCK(dev);
207235783Skib		return ENOMEM;
208235783Skib	}
209235783Skib
210235783Skib	i = 0;
211235783Skib	TAILQ_FOREACH(map, &dev->maplist, link)
212235783Skib		tempmaps[i++] = *map;
213235783Skib
214235783Skib	DRM_UNLOCK(dev);
215235783Skib
216235783Skib	DRM_SYSCTL_PRINT("\nslot offset	        size       "
217235783Skib	    "type flags address            handle mtrr\n");
218235783Skib
219235783Skib	for (i = 0; i < mapcount; i++) {
220235783Skib		map = &tempmaps[i];
221235783Skib
222255012Sjkim		switch(map->type) {
223255012Sjkim		default:
224235783Skib			type = "??";
225255012Sjkim			break;
226255012Sjkim		case _DRM_FRAME_BUFFER:
227255012Sjkim		case _DRM_REGISTERS:
228255012Sjkim		case _DRM_SHM:
229255012Sjkim		case _DRM_AGP:
230255012Sjkim		case _DRM_SCATTER_GATHER:
231255012Sjkim		case _DRM_CONSISTENT:
232255012Sjkim		case _DRM_GEM:
233235783Skib			type = types[map->type];
234255012Sjkim			break;
235255012Sjkim		}
236235783Skib
237235783Skib		if (!map->mtrr)
238235783Skib			yesno = "no";
239235783Skib		else
240235783Skib			yesno = "yes";
241235783Skib
242235783Skib		DRM_SYSCTL_PRINT(
243235783Skib		    "%4d 0x%016lx 0x%08lx %4.4s  0x%02x 0x%016lx %6d %s\n",
244235783Skib		    i, map->offset, map->size, type, map->flags,
245235783Skib		    (unsigned long)map->virtual,
246235783Skib		    (unsigned int)((unsigned long)map->handle >>
247235783Skib		    DRM_MAP_HANDLE_SHIFT), yesno);
248235783Skib	}
249235783Skib	SYSCTL_OUT(req, "", 1);
250235783Skib
251235783Skibdone:
252235783Skib	free(tempmaps, DRM_MEM_DRIVER);
253235783Skib	return retcode;
254235783Skib}
255235783Skib
256235783Skibstatic int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
257235783Skib{
258235783Skib	struct drm_device	 *dev = arg1;
259235783Skib	drm_device_dma_t *dma = dev->dma;
260235783Skib	drm_device_dma_t tempdma;
261235783Skib	int *templists;
262235783Skib	int i;
263235783Skib	char buf[128];
264235783Skib	int retcode;
265235783Skib
266235783Skib	/* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
267235783Skib	 * copy of the whole structure and the relevant data from buflist.
268235783Skib	 */
269235783Skib	DRM_LOCK(dev);
270235783Skib	if (dma == NULL) {
271235783Skib		DRM_UNLOCK(dev);
272235783Skib		return 0;
273235783Skib	}
274235783Skib	DRM_SPINLOCK(&dev->dma_lock);
275235783Skib	tempdma = *dma;
276235783Skib	templists = malloc(sizeof(int) * dma->buf_count, DRM_MEM_DRIVER,
277235783Skib	    M_NOWAIT);
278235783Skib	for (i = 0; i < dma->buf_count; i++)
279235783Skib		templists[i] = dma->buflist[i]->list;
280235783Skib	dma = &tempdma;
281235783Skib	DRM_SPINUNLOCK(&dev->dma_lock);
282235783Skib	DRM_UNLOCK(dev);
283235783Skib
284235783Skib	DRM_SYSCTL_PRINT("\n o     size count  free	 segs pages    kB\n");
285235783Skib	for (i = 0; i <= DRM_MAX_ORDER; i++) {
286235783Skib		if (dma->bufs[i].buf_count)
287235783Skib			DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
288235783Skib				       i,
289235783Skib				       dma->bufs[i].buf_size,
290235783Skib				       dma->bufs[i].buf_count,
291235783Skib				       atomic_read(&dma->bufs[i]
292235783Skib						   .freelist.count),
293235783Skib				       dma->bufs[i].seg_count,
294235783Skib				       dma->bufs[i].seg_count
295235783Skib				       *(1 << dma->bufs[i].page_order),
296235783Skib				       (dma->bufs[i].seg_count
297235783Skib					* (1 << dma->bufs[i].page_order))
298235783Skib				       * (int)PAGE_SIZE / 1024);
299235783Skib	}
300235783Skib	DRM_SYSCTL_PRINT("\n");
301235783Skib	for (i = 0; i < dma->buf_count; i++) {
302235783Skib		if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
303235783Skib		DRM_SYSCTL_PRINT(" %d", templists[i]);
304235783Skib	}
305235783Skib	DRM_SYSCTL_PRINT("\n");
306235783Skib
307235783Skib	SYSCTL_OUT(req, "", 1);
308235783Skibdone:
309235783Skib	free(templists, DRM_MEM_DRIVER);
310235783Skib	return retcode;
311235783Skib}
312235783Skib
313235783Skibstatic int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
314235783Skib{
315235783Skib	struct drm_device *dev = arg1;
316235783Skib	struct drm_file *priv, *tempprivs;
317235783Skib	char buf[128];
318235783Skib	int retcode;
319235783Skib	int privcount, i;
320235783Skib
321235783Skib	DRM_LOCK(dev);
322235783Skib
323235783Skib	privcount = 0;
324235783Skib	TAILQ_FOREACH(priv, &dev->files, link)
325235783Skib		privcount++;
326235783Skib
327235783Skib	tempprivs = malloc(sizeof(struct drm_file) * privcount, DRM_MEM_DRIVER,
328235783Skib	    M_NOWAIT);
329235783Skib	if (tempprivs == NULL) {
330235783Skib		DRM_UNLOCK(dev);
331235783Skib		return ENOMEM;
332235783Skib	}
333235783Skib	i = 0;
334235783Skib	TAILQ_FOREACH(priv, &dev->files, link)
335235783Skib		tempprivs[i++] = *priv;
336235783Skib
337235783Skib	DRM_UNLOCK(dev);
338235783Skib
339235783Skib	DRM_SYSCTL_PRINT(
340235783Skib	    "\na dev            pid   uid      magic     ioctls\n");
341235783Skib	for (i = 0; i < privcount; i++) {
342235783Skib		priv = &tempprivs[i];
343235783Skib		DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n",
344235783Skib			       priv->authenticated ? 'y' : 'n',
345235783Skib			       devtoname(priv->dev->devnode),
346235783Skib			       priv->pid,
347235783Skib			       priv->uid,
348235783Skib			       priv->magic,
349235783Skib			       priv->ioctl_count);
350235783Skib	}
351235783Skib
352235783Skib	SYSCTL_OUT(req, "", 1);
353235783Skibdone:
354235783Skib	free(tempprivs, DRM_MEM_DRIVER);
355235783Skib	return retcode;
356235783Skib}
357235783Skib
358235783Skibstatic int drm_vblank_info DRM_SYSCTL_HANDLER_ARGS
359235783Skib{
360235783Skib	struct drm_device *dev = arg1;
361235783Skib	char buf[128];
362235783Skib	int retcode;
363235783Skib	int i;
364235783Skib
365235783Skib	DRM_SYSCTL_PRINT("\ncrtc ref count    last     enabled inmodeset\n");
366235783Skib	DRM_LOCK(dev);
367235783Skib	if (dev->_vblank_count == NULL)
368235783Skib		goto done;
369235783Skib	for (i = 0 ; i < dev->num_crtcs ; i++) {
370235783Skib		DRM_SYSCTL_PRINT("  %02d  %02d %08d %08d %02d      %02d\n",
371235783Skib		    i, dev->vblank_refcount[i],
372235783Skib		    dev->_vblank_count[i],
373235783Skib		    dev->last_vblank[i],
374235783Skib		    dev->vblank_enabled[i],
375235783Skib		    dev->vblank_inmodeset[i]);
376235783Skib	}
377235783Skibdone:
378235783Skib	DRM_UNLOCK(dev);
379235783Skib
380235783Skib	SYSCTL_OUT(req, "", -1);
381235783Skib	return retcode;
382235783Skib}
383