xref: /freebsd-12.1/sys/dev/drm/drm_sysctl.c (revision dfd1ff19)
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.
22  */
23 
24 #include <sys/cdefs.h>
25 __FBSDID("$FreeBSD$");
26 
27 #include "dev/drm/drmP.h"
28 #include "dev/drm/drm.h"
29 
30 #include <sys/sysctl.h>
31 
32 static int	   drm_name_info DRM_SYSCTL_HANDLER_ARGS;
33 static int	   drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
34 static int	   drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
35 static int	   drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
36 
37 struct drm_sysctl_list {
38 	const char *name;
39 	int	   (*f) DRM_SYSCTL_HANDLER_ARGS;
40 } drm_sysctl_list[] = {
41 	{"name",    drm_name_info},
42 	{"vm",	    drm_vm_info},
43 	{"clients", drm_clients_info},
44 	{"bufs",    drm_bufs_info},
45 };
46 #define DRM_SYSCTL_ENTRIES (sizeof(drm_sysctl_list)/sizeof(drm_sysctl_list[0]))
47 
48 struct drm_sysctl_info {
49 	struct sysctl_ctx_list ctx;
50 	char		       name[2];
51 };
52 
53 int drm_sysctl_init(drm_device_t *dev)
54 {
55 	struct drm_sysctl_info *info;
56 	struct sysctl_oid *oid;
57 	struct sysctl_oid *top, *drioid;
58 	int		  i;
59 
60 	info = malloc(sizeof *info, M_DRM, M_WAITOK | M_ZERO);
61 	if ( !info )
62 		return 1;
63 	dev->sysctl = info;
64 
65 	/* Add the sysctl node for DRI if it doesn't already exist */
66 	drioid = SYSCTL_ADD_NODE( &info->ctx, &sysctl__hw_children, OID_AUTO, "dri", CTLFLAG_RW, NULL, "DRI Graphics");
67 	if (!drioid)
68 		return 1;
69 
70 	/* Find the next free slot under hw.dri */
71 	i = 0;
72 	SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) {
73 		if (i <= oid->oid_arg2)
74 			i = oid->oid_arg2 + 1;
75 	}
76 	if (i>9)
77 		return 1;
78 
79 	/* Add the hw.dri.x for our device */
80 	info->name[0] = '0' + i;
81 	info->name[1] = 0;
82 	top = SYSCTL_ADD_NODE( &info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
83 	if (!top)
84 		return 1;
85 
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_INT | CTLFLAG_RD,
92 			dev,
93 			0,
94 			drm_sysctl_list[i].f,
95 			"A",
96 			NULL);
97 		if (!oid)
98 			return 1;
99 	}
100 	SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(top), OID_AUTO, "debug",
101 	    CTLFLAG_RW, &drm_debug_flag, sizeof(drm_debug_flag),
102 	    "Enable debugging output");
103 
104 	return 0;
105 }
106 
107 int drm_sysctl_cleanup(drm_device_t *dev)
108 {
109 	int error;
110 	error = sysctl_ctx_free( &dev->sysctl->ctx );
111 
112 	free(dev->sysctl, M_DRM);
113 	dev->sysctl = NULL;
114 
115 	return error;
116 }
117 
118 #define DRM_SYSCTL_PRINT(fmt, arg...)				\
119 do {								\
120 	snprintf(buf, sizeof(buf), fmt, ##arg);			\
121 	retcode = SYSCTL_OUT(req, buf, strlen(buf));		\
122 	if (retcode)						\
123 		goto done;					\
124 } while (0)
125 
126 static int drm_name_info DRM_SYSCTL_HANDLER_ARGS
127 {
128 	drm_device_t *dev = arg1;
129 	char buf[128];
130 	int retcode;
131 	int hasunique = 0;
132 
133 	DRM_SYSCTL_PRINT("%s 0x%x", dev->driver.name, dev2udev(dev->devnode));
134 
135 	DRM_LOCK();
136 	if (dev->unique) {
137 		snprintf(buf, sizeof(buf), " %s", dev->unique);
138 		hasunique = 1;
139 	}
140 	DRM_UNLOCK();
141 
142 	if (hasunique)
143 		SYSCTL_OUT(req, buf, strlen(buf));
144 
145 	SYSCTL_OUT(req, "", 1);
146 
147 done:
148 	return retcode;
149 }
150 
151 static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
152 {
153 	drm_device_t *dev = arg1;
154 	drm_local_map_t *map, *tempmaps;
155 	const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
156 	const char *type, *yesno;
157 	int i, mapcount;
158 	char buf[128];
159 	int retcode;
160 
161 	/* We can't hold the lock while doing SYSCTL_OUTs, so allocate a
162 	 * temporary copy of all the map entries and then SYSCTL_OUT that.
163 	 */
164 	DRM_LOCK();
165 
166 	mapcount = 0;
167 	TAILQ_FOREACH(map, &dev->maplist, link)
168 		mapcount++;
169 
170 	tempmaps = malloc(sizeof(drm_local_map_t) * mapcount, M_DRM, M_NOWAIT);
171 	if (tempmaps == NULL) {
172 		DRM_UNLOCK();
173 		return ENOMEM;
174 	}
175 
176 	i = 0;
177 	TAILQ_FOREACH(map, &dev->maplist, link)
178 		tempmaps[i++] = *map;
179 
180 	DRM_UNLOCK();
181 
182 	DRM_SYSCTL_PRINT("\nslot	 offset	      size type flags	 "
183 			 "address mtrr\n");
184 
185 	for (i = 0; i < mapcount; i++) {
186 		map = &tempmaps[i];
187 
188 		if (map->type < 0 || map->type > 4)
189 			type = "??";
190 		else
191 			type = types[map->type];
192 
193 		if (!map->mtrr)
194 			yesno = "no";
195 		else
196 			yesno = "yes";
197 
198 		DRM_SYSCTL_PRINT(
199 		    "%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx %s\n", i,
200 		    map->offset, map->size, type, map->flags,
201 		    (unsigned long)map->handle, yesno);
202 	}
203 	SYSCTL_OUT(req, "", 1);
204 
205 done:
206 	free(tempmaps, M_DRM);
207 	return retcode;
208 }
209 
210 static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
211 {
212 	drm_device_t	 *dev = arg1;
213 	drm_device_dma_t *dma = dev->dma;
214 	drm_device_dma_t tempdma;
215 	int *templists;
216 	int i;
217 	char buf[128];
218 	int retcode;
219 
220 	/* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
221 	 * copy of the whole structure and the relevant data from buflist.
222 	 */
223 	DRM_LOCK();
224 	if (dma == NULL) {
225 		DRM_UNLOCK();
226 		return 0;
227 	}
228 	DRM_SPINLOCK(&dev->dma_lock);
229 	tempdma = *dma;
230 	templists = malloc(sizeof(int) * dma->buf_count, M_DRM, M_NOWAIT);
231 	for (i = 0; i < dma->buf_count; i++)
232 		templists[i] = dma->buflist[i]->list;
233 	dma = &tempdma;
234 	DRM_SPINUNLOCK(&dev->dma_lock);
235 	DRM_UNLOCK();
236 
237 	DRM_SYSCTL_PRINT("\n o     size count  free	 segs pages    kB\n");
238 	for (i = 0; i <= DRM_MAX_ORDER; i++) {
239 		if (dma->bufs[i].buf_count)
240 			DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
241 				       i,
242 				       dma->bufs[i].buf_size,
243 				       dma->bufs[i].buf_count,
244 				       atomic_read(&dma->bufs[i]
245 						   .freelist.count),
246 				       dma->bufs[i].seg_count,
247 				       dma->bufs[i].seg_count
248 				       *(1 << dma->bufs[i].page_order),
249 				       (dma->bufs[i].seg_count
250 					* (1 << dma->bufs[i].page_order))
251 				       * PAGE_SIZE / 1024);
252 	}
253 	DRM_SYSCTL_PRINT("\n");
254 	for (i = 0; i < dma->buf_count; i++) {
255 		if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
256 		DRM_SYSCTL_PRINT(" %d", templists[i]);
257 	}
258 	DRM_SYSCTL_PRINT("\n");
259 
260 	SYSCTL_OUT(req, "", 1);
261 done:
262 	free(templists, M_DRM);
263 	return retcode;
264 }
265 
266 static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
267 {
268 	drm_device_t *dev = arg1;
269 	drm_file_t *priv, *tempprivs;
270 	char buf[128];
271 	int retcode;
272 	int privcount, i;
273 
274 	DRM_LOCK();
275 
276 	privcount = 0;
277 	TAILQ_FOREACH(priv, &dev->files, link)
278 		privcount++;
279 
280 	tempprivs = malloc(sizeof(drm_file_t) * privcount, M_DRM, M_NOWAIT);
281 	if (tempprivs == NULL) {
282 		DRM_UNLOCK();
283 		return ENOMEM;
284 	}
285 	i = 0;
286 	TAILQ_FOREACH(priv, &dev->files, link)
287 		tempprivs[i++] = *priv;
288 
289 	DRM_UNLOCK();
290 
291 	DRM_SYSCTL_PRINT("\na dev	pid    uid	magic	  ioctls\n");
292 	for (i = 0; i < privcount; i++) {
293 		priv = &tempprivs[i];
294 		DRM_SYSCTL_PRINT("%c %3d %5d %5d %10u %10lu\n",
295 			       priv->authenticated ? 'y' : 'n',
296 			       priv->minor,
297 			       priv->pid,
298 			       priv->uid,
299 			       priv->magic,
300 			       priv->ioctl_count);
301 	}
302 
303 	SYSCTL_OUT(req, "", 1);
304 done:
305 	free(tempprivs, M_DRM);
306 	return retcode;
307 }
308