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