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