17f3c3d6fSHasso Tepper /*- 27f3c3d6fSHasso Tepper * Copyright 2003 Eric Anholt 37f3c3d6fSHasso Tepper * All Rights Reserved. 47f3c3d6fSHasso Tepper * 57f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a 67f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"), 77f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation 87f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense, 97f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the 107f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions: 117f3c3d6fSHasso Tepper * 127f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next 137f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the 147f3c3d6fSHasso Tepper * Software. 157f3c3d6fSHasso Tepper * 167f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 197f3c3d6fSHasso Tepper * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 207f3c3d6fSHasso Tepper * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 217f3c3d6fSHasso Tepper * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 225718399fSFrançois Tigeot * 235718399fSFrançois Tigeot * $FreeBSD: src/sys/dev/drm2/drm_sysctl.c,v 1.1 2012/05/22 11:07:44 kib Exp $ 247f3c3d6fSHasso Tepper */ 257f3c3d6fSHasso Tepper 267f3c3d6fSHasso Tepper /** @file drm_sysctl.c 277f3c3d6fSHasso Tepper * Implementation of various sysctls for controlling DRM behavior and reporting 287f3c3d6fSHasso Tepper * debug information. 297f3c3d6fSHasso Tepper */ 307f3c3d6fSHasso Tepper 315718399fSFrançois Tigeot #include <sys/conf.h> 325718399fSFrançois Tigeot #include <sys/sysctl.h> 335718399fSFrançois Tigeot #include <sys/types.h> 345718399fSFrançois Tigeot 3518e26a6dSFrançois Tigeot #include <drm/drmP.h> 367f3c3d6fSHasso Tepper 377f3c3d6fSHasso Tepper static int drm_name_info DRM_SYSCTL_HANDLER_ARGS; 387f3c3d6fSHasso Tepper static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS; 397f3c3d6fSHasso Tepper static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS; 407f3c3d6fSHasso Tepper static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS; 417f3c3d6fSHasso Tepper 427f3c3d6fSHasso Tepper struct drm_sysctl_list { 437f3c3d6fSHasso Tepper const char *name; 447f3c3d6fSHasso Tepper int (*f) DRM_SYSCTL_HANDLER_ARGS; 457f3c3d6fSHasso Tepper } drm_sysctl_list[] = { 467f3c3d6fSHasso Tepper {"name", drm_name_info}, 477f3c3d6fSHasso Tepper {"vm", drm_vm_info}, 487f3c3d6fSHasso Tepper {"clients", drm_clients_info}, 497f3c3d6fSHasso Tepper {"bufs", drm_bufs_info}, 507f3c3d6fSHasso Tepper }; 51c157ff7aSSascha Wildner #define DRM_SYSCTL_ENTRIES NELEM(drm_sysctl_list) 527f3c3d6fSHasso Tepper 53b3705d71SHasso Tepper int drm_sysctl_init(struct drm_device *dev) 547f3c3d6fSHasso Tepper { 557f3c3d6fSHasso Tepper struct drm_sysctl_info *info; 567f3c3d6fSHasso Tepper struct sysctl_oid *oid; 577f3c3d6fSHasso Tepper struct sysctl_oid *top, *drioid; 587f3c3d6fSHasso Tepper int i; 597f3c3d6fSHasso Tepper 605a3b77d5SFrançois Tigeot info = kmalloc(sizeof *info, M_DRM, M_WAITOK | M_ZERO); 617f3c3d6fSHasso Tepper if ( !info ) 627f3c3d6fSHasso Tepper return 1; 637f3c3d6fSHasso Tepper dev->sysctl = info; 647f3c3d6fSHasso Tepper 657f3c3d6fSHasso Tepper /* Add the sysctl node for DRI if it doesn't already exist */ 665718399fSFrançois Tigeot drioid = SYSCTL_ADD_NODE(&info->ctx, &sysctl__hw_children, OID_AUTO, 675718399fSFrançois Tigeot "dri", CTLFLAG_RW, NULL, "DRI Graphics"); 687f3c3d6fSHasso Tepper if (!drioid) 697f3c3d6fSHasso Tepper return 1; 707f3c3d6fSHasso Tepper 717f3c3d6fSHasso Tepper /* Find the next free slot under hw.dri */ 727f3c3d6fSHasso Tepper i = 0; 737f3c3d6fSHasso Tepper SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) { 747f3c3d6fSHasso Tepper if (i <= oid->oid_arg2) 757f3c3d6fSHasso Tepper i = oid->oid_arg2 + 1; 767f3c3d6fSHasso Tepper } 777f3c3d6fSHasso Tepper if (i>9) 787f3c3d6fSHasso Tepper return 1; 797f3c3d6fSHasso Tepper 805718399fSFrançois Tigeot dev->sysctl_node_idx = i; 817f3c3d6fSHasso Tepper /* Add the hw.dri.x for our device */ 827f3c3d6fSHasso Tepper info->name[0] = '0' + i; 837f3c3d6fSHasso Tepper info->name[1] = 0; 845718399fSFrançois Tigeot top = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(drioid), 855718399fSFrançois Tigeot OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL); 867f3c3d6fSHasso Tepper if (!top) 877f3c3d6fSHasso Tepper return 1; 887f3c3d6fSHasso Tepper 897f3c3d6fSHasso Tepper for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) { 907f3c3d6fSHasso Tepper oid = SYSCTL_ADD_OID(&info->ctx, 917f3c3d6fSHasso Tepper SYSCTL_CHILDREN(top), 927f3c3d6fSHasso Tepper OID_AUTO, 937f3c3d6fSHasso Tepper drm_sysctl_list[i].name, 9499f70504SFrançois Tigeot CTLTYPE_STRING | CTLFLAG_RD, 957f3c3d6fSHasso Tepper dev, 967f3c3d6fSHasso Tepper 0, 977f3c3d6fSHasso Tepper drm_sysctl_list[i].f, 987f3c3d6fSHasso Tepper "A", 997f3c3d6fSHasso Tepper NULL); 1007f3c3d6fSHasso Tepper if (!oid) 1017f3c3d6fSHasso Tepper return 1; 1027f3c3d6fSHasso Tepper } 1035718399fSFrançois Tigeot SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "debug", 1041d5dd71dSFrançois Tigeot CTLFLAG_RW, &drm_debug, sizeof(drm_debug), 1057f3c3d6fSHasso Tepper "Enable debugging output"); 1065718399fSFrançois Tigeot SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "notyet", 1071d5dd71dSFrançois Tigeot CTLFLAG_RW, &drm_notyet_flag, sizeof(drm_debug), 1085718399fSFrançois Tigeot "Enable notyet reminders"); 1097f3c3d6fSHasso Tepper 1105718399fSFrançois Tigeot if (dev->driver->sysctl_init != NULL) 1115718399fSFrançois Tigeot dev->driver->sysctl_init(dev, &info->ctx, top); 1125718399fSFrançois Tigeot 1135718399fSFrançois Tigeot SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, 1145718399fSFrançois Tigeot "vblank_offdelay", CTLFLAG_RW, &drm_vblank_offdelay, 1155718399fSFrançois Tigeot sizeof(drm_vblank_offdelay), 1165718399fSFrançois Tigeot ""); 1175718399fSFrançois Tigeot SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, 1185718399fSFrançois Tigeot "timestamp_precision", CTLFLAG_RW, &drm_timestamp_precision, 1195718399fSFrançois Tigeot sizeof(drm_timestamp_precision), 1205718399fSFrançois Tigeot ""); 1215718399fSFrançois Tigeot 1225718399fSFrançois Tigeot return (0); 1237f3c3d6fSHasso Tepper } 1247f3c3d6fSHasso Tepper 125b3705d71SHasso Tepper int drm_sysctl_cleanup(struct drm_device *dev) 1267f3c3d6fSHasso Tepper { 1277f3c3d6fSHasso Tepper int error; 1285718399fSFrançois Tigeot 1297f3c3d6fSHasso Tepper error = sysctl_ctx_free(&dev->sysctl->ctx); 1305a3b77d5SFrançois Tigeot drm_free(dev->sysctl, M_DRM); 1317f3c3d6fSHasso Tepper dev->sysctl = NULL; 1325718399fSFrançois Tigeot if (dev->driver->sysctl_cleanup != NULL) 1335718399fSFrançois Tigeot dev->driver->sysctl_cleanup(dev); 1347f3c3d6fSHasso Tepper 1355718399fSFrançois Tigeot return (error); 1367f3c3d6fSHasso Tepper } 1377f3c3d6fSHasso Tepper 1387f3c3d6fSHasso Tepper #define DRM_SYSCTL_PRINT(fmt, arg...) \ 1397f3c3d6fSHasso Tepper do { \ 1405718399fSFrançois Tigeot ksnprintf(buf, sizeof(buf), fmt, ##arg); \ 1417f3c3d6fSHasso Tepper retcode = SYSCTL_OUT(req, buf, strlen(buf)); \ 1427f3c3d6fSHasso Tepper if (retcode) \ 1437f3c3d6fSHasso Tepper goto done; \ 1447f3c3d6fSHasso Tepper } while (0) 1457f3c3d6fSHasso Tepper 1467f3c3d6fSHasso Tepper static int drm_name_info DRM_SYSCTL_HANDLER_ARGS 1477f3c3d6fSHasso Tepper { 148b3705d71SHasso Tepper struct drm_device *dev = arg1; 1497f3c3d6fSHasso Tepper char buf[128]; 1507f3c3d6fSHasso Tepper int retcode; 1517f3c3d6fSHasso Tepper int hasunique = 0; 1527f3c3d6fSHasso Tepper 153b3705d71SHasso Tepper DRM_SYSCTL_PRINT("%s 0x%x", dev->driver->name, dev2udev(dev->devnode)); 1547f3c3d6fSHasso Tepper 1555718399fSFrançois Tigeot DRM_LOCK(dev); 1567f3c3d6fSHasso Tepper if (dev->unique) { 1575718399fSFrançois Tigeot ksnprintf(buf, sizeof(buf), " %s", dev->unique); 1587f3c3d6fSHasso Tepper hasunique = 1; 1597f3c3d6fSHasso Tepper } 1605718399fSFrançois Tigeot DRM_UNLOCK(dev); 1617f3c3d6fSHasso Tepper 1627f3c3d6fSHasso Tepper if (hasunique) 1637f3c3d6fSHasso Tepper SYSCTL_OUT(req, buf, strlen(buf)); 1647f3c3d6fSHasso Tepper 1657f3c3d6fSHasso Tepper SYSCTL_OUT(req, "", 1); 1667f3c3d6fSHasso Tepper 1677f3c3d6fSHasso Tepper done: 1687f3c3d6fSHasso Tepper return retcode; 1697f3c3d6fSHasso Tepper } 1707f3c3d6fSHasso Tepper 171f599cd46SFrançois Tigeot /** 172f599cd46SFrançois Tigeot * Called when "/proc/dri/.../vm" is read. 173f599cd46SFrançois Tigeot * 174f599cd46SFrançois Tigeot * Prints information about all mappings in drm_device::maplist. 175f599cd46SFrançois Tigeot */ 1767f3c3d6fSHasso Tepper static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS 1777f3c3d6fSHasso Tepper { 1787f3c3d6fSHasso Tepper char buf[128]; 1797f3c3d6fSHasso Tepper int retcode; 180f599cd46SFrançois Tigeot struct drm_device *dev = arg1; 181f599cd46SFrançois Tigeot struct drm_local_map *map; 182f599cd46SFrançois Tigeot struct drm_map_list *r_list; 1837f3c3d6fSHasso Tepper 184f599cd46SFrançois Tigeot /* Hardcoded from _DRM_FRAME_BUFFER, 185f599cd46SFrançois Tigeot _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and 186f599cd46SFrançois Tigeot _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ 187f599cd46SFrançois Tigeot const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; 188f599cd46SFrançois Tigeot const char *type; 189f599cd46SFrançois Tigeot int i; 190f599cd46SFrançois Tigeot 1915718399fSFrançois Tigeot DRM_LOCK(dev); 192b3705d71SHasso Tepper DRM_SYSCTL_PRINT("\nslot offset size " 19399f70504SFrançois Tigeot "type flags address handle mtrr\n"); 194f599cd46SFrançois Tigeot i = 0; 195f599cd46SFrançois Tigeot list_for_each_entry(r_list, &dev->maplist, head) { 196f599cd46SFrançois Tigeot map = r_list->map; 197f599cd46SFrançois Tigeot if (!map) 198f599cd46SFrançois Tigeot continue; 199f599cd46SFrançois Tigeot if (map->type < 0 || map->type > 5) 2007f3c3d6fSHasso Tepper type = "??"; 2017f3c3d6fSHasso Tepper else 202f599cd46SFrançois Tigeot type = types[map->type]; 2037f3c3d6fSHasso Tepper 204f599cd46SFrançois Tigeot DRM_SYSCTL_PRINT("%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ", 205f599cd46SFrançois Tigeot i, 206f599cd46SFrançois Tigeot (unsigned long long)map->offset, 207f599cd46SFrançois Tigeot map->size, type, map->flags, 208f599cd46SFrançois Tigeot (unsigned long) r_list->user_token); 209f599cd46SFrançois Tigeot if (map->mtrr < 0) 210f599cd46SFrançois Tigeot DRM_SYSCTL_PRINT("none\n"); 211f599cd46SFrançois Tigeot else 212f599cd46SFrançois Tigeot DRM_SYSCTL_PRINT("%4d\n", map->mtrr); 213f599cd46SFrançois Tigeot i++; 214f599cd46SFrançois Tigeot 2157f3c3d6fSHasso Tepper } 2167f3c3d6fSHasso Tepper SYSCTL_OUT(req, "", 1); 217f599cd46SFrançois Tigeot DRM_UNLOCK(dev); 2187f3c3d6fSHasso Tepper 2197f3c3d6fSHasso Tepper done: 220f599cd46SFrançois Tigeot return 0; 2217f3c3d6fSHasso Tepper } 2227f3c3d6fSHasso Tepper 2237f3c3d6fSHasso Tepper static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS 2247f3c3d6fSHasso Tepper { 225b3705d71SHasso Tepper struct drm_device *dev = arg1; 2267f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 2277f3c3d6fSHasso Tepper drm_device_dma_t tempdma; 2287f3c3d6fSHasso Tepper int *templists; 2297f3c3d6fSHasso Tepper int i; 2307f3c3d6fSHasso Tepper char buf[128]; 2317f3c3d6fSHasso Tepper int retcode; 2327f3c3d6fSHasso Tepper 2337f3c3d6fSHasso Tepper /* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary 2347f3c3d6fSHasso Tepper * copy of the whole structure and the relevant data from buflist. 2357f3c3d6fSHasso Tepper */ 2365718399fSFrançois Tigeot DRM_LOCK(dev); 2377f3c3d6fSHasso Tepper if (dma == NULL) { 2385718399fSFrançois Tigeot DRM_UNLOCK(dev); 2397f3c3d6fSHasso Tepper return 0; 2407f3c3d6fSHasso Tepper } 2415718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 2427f3c3d6fSHasso Tepper tempdma = *dma; 2435a3b77d5SFrançois Tigeot templists = kmalloc(sizeof(int) * dma->buf_count, M_DRM, 244f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK); 2457f3c3d6fSHasso Tepper for (i = 0; i < dma->buf_count; i++) 2467f3c3d6fSHasso Tepper templists[i] = dma->buflist[i]->list; 2477f3c3d6fSHasso Tepper dma = &tempdma; 2485718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 2495718399fSFrançois Tigeot DRM_UNLOCK(dev); 2507f3c3d6fSHasso Tepper 2517f3c3d6fSHasso Tepper DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n"); 2527f3c3d6fSHasso Tepper for (i = 0; i <= DRM_MAX_ORDER; i++) { 2537f3c3d6fSHasso Tepper if (dma->bufs[i].buf_count) 254*24edb884SFrançois Tigeot DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d\n", 2557f3c3d6fSHasso Tepper i, 2567f3c3d6fSHasso Tepper dma->bufs[i].buf_size, 2577f3c3d6fSHasso Tepper dma->bufs[i].buf_count, 2587f3c3d6fSHasso Tepper dma->bufs[i].seg_count, 2597f3c3d6fSHasso Tepper dma->bufs[i].seg_count 2607f3c3d6fSHasso Tepper *(1 << dma->bufs[i].page_order), 2617f3c3d6fSHasso Tepper (dma->bufs[i].seg_count 2627f3c3d6fSHasso Tepper * (1 << dma->bufs[i].page_order)) 2635718399fSFrançois Tigeot * (int)PAGE_SIZE / 1024); 2647f3c3d6fSHasso Tepper } 2657f3c3d6fSHasso Tepper DRM_SYSCTL_PRINT("\n"); 2667f3c3d6fSHasso Tepper for (i = 0; i < dma->buf_count; i++) { 2677f3c3d6fSHasso Tepper if (i && !(i%32)) DRM_SYSCTL_PRINT("\n"); 2687f3c3d6fSHasso Tepper DRM_SYSCTL_PRINT(" %d", templists[i]); 2697f3c3d6fSHasso Tepper } 2707f3c3d6fSHasso Tepper DRM_SYSCTL_PRINT("\n"); 2717f3c3d6fSHasso Tepper 2727f3c3d6fSHasso Tepper SYSCTL_OUT(req, "", 1); 2737f3c3d6fSHasso Tepper done: 2745a3b77d5SFrançois Tigeot drm_free(templists, M_DRM); 2757f3c3d6fSHasso Tepper return retcode; 2767f3c3d6fSHasso Tepper } 2777f3c3d6fSHasso Tepper 2787f3c3d6fSHasso Tepper static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS 2797f3c3d6fSHasso Tepper { 280b3705d71SHasso Tepper struct drm_device *dev = arg1; 281b3705d71SHasso Tepper struct drm_file *priv, *tempprivs; 2827f3c3d6fSHasso Tepper char buf[128]; 2837f3c3d6fSHasso Tepper int retcode; 2847f3c3d6fSHasso Tepper int privcount, i; 2857f3c3d6fSHasso Tepper 2865718399fSFrançois Tigeot DRM_LOCK(dev); 2877f3c3d6fSHasso Tepper 2887f3c3d6fSHasso Tepper privcount = 0; 2891610a1a0SFrançois Tigeot list_for_each_entry(priv, &dev->filelist, lhead) 2907f3c3d6fSHasso Tepper privcount++; 2917f3c3d6fSHasso Tepper 2925a3b77d5SFrançois Tigeot tempprivs = kmalloc(sizeof(struct drm_file) * privcount, M_DRM, 293f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK); 2947f3c3d6fSHasso Tepper if (tempprivs == NULL) { 2955718399fSFrançois Tigeot DRM_UNLOCK(dev); 2967f3c3d6fSHasso Tepper return ENOMEM; 2977f3c3d6fSHasso Tepper } 2987f3c3d6fSHasso Tepper i = 0; 2991610a1a0SFrançois Tigeot list_for_each_entry(priv, &dev->filelist, lhead) 3007f3c3d6fSHasso Tepper tempprivs[i++] = *priv; 3017f3c3d6fSHasso Tepper 3025718399fSFrançois Tigeot DRM_UNLOCK(dev); 3037f3c3d6fSHasso Tepper 3045718399fSFrançois Tigeot DRM_SYSCTL_PRINT( 3055718399fSFrançois Tigeot "\na dev pid uid magic ioctls\n"); 3067f3c3d6fSHasso Tepper for (i = 0; i < privcount; i++) { 3077f3c3d6fSHasso Tepper priv = &tempprivs[i]; 3085718399fSFrançois Tigeot DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n", 3097f3c3d6fSHasso Tepper priv->authenticated ? 'y' : 'n', 31079f713b0SFrançois Tigeot devtoname(priv->dev->devnode), 3117f3c3d6fSHasso Tepper priv->pid, 3127f3c3d6fSHasso Tepper priv->uid, 3137f3c3d6fSHasso Tepper priv->magic, 3147f3c3d6fSHasso Tepper priv->ioctl_count); 3157f3c3d6fSHasso Tepper } 3167f3c3d6fSHasso Tepper 3177f3c3d6fSHasso Tepper SYSCTL_OUT(req, "", 1); 3187f3c3d6fSHasso Tepper done: 3195a3b77d5SFrançois Tigeot drm_free(tempprivs, M_DRM); 3207f3c3d6fSHasso Tepper return retcode; 3217f3c3d6fSHasso Tepper } 322