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