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