From 7e1ef488d47fb455db37d264e437e6ca23ee11f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Ondra=C4=8Dka?= Date: Thu, 9 Apr 2026 14:10:53 +0200 Subject: [PATCH 1/2] winsys/radeon: Extract BO import ref helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pavel Ondračka --- src/gallium/winsys/radeon/drm/radeon_drm_bo.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c index 50a08c8fa3d..59a35923c4b 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c @@ -33,6 +33,18 @@ static inline struct radeon_bo *radeon_bo(struct pb_buffer_lean *bo) return (struct radeon_bo *)bo; } +static bool +radeon_bo_ref_existing(struct radeon_bo *bo) +{ + if (unlikely(p_atomic_inc_return(&bo->base.reference.count) == 1)) { + p_atomic_dec(&bo->base.reference.count); + assert(p_atomic_read(&bo->base.reference.count) == 0); + return false; + } + + return true; +} + struct radeon_bo_va_hole { struct list_head list; uint64_t offset; @@ -1184,13 +1196,8 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_handle(struct radeon_winsys } if (bo) { - /* Increase the refcount. */ - if (unlikely(p_atomic_inc_return(&bo->base.reference.count) == 1)) { - p_atomic_dec(&bo->base.reference.count); - assert(p_atomic_read(&bo->base.reference.count) == 0); - } else { + if (radeon_bo_ref_existing(bo)) goto done; - } } /* There isn't, create a new one. */ From 52a624ebdf216bf051c70628b09443ef2a4a2b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Ondra=C4=8Dka?= Date: Fri, 27 Mar 2026 18:20:56 +0100 Subject: [PATCH 2/2] winsys/radeon: Prefer a render node FD for internal work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the FD passed in isn't from a render node, try to determine the corresponding render node and open it. If that succeeds, use the render node FD for internal driver operations, while keeping the original FD for application-facing KMS and flink operations. This avoids issues with unauthenticated card-node FDs, e.g. GBM platform probing via eglinfo in a desktop session as a non-root user. Compared to the analogous amdgpu change, the radeon winsys needs some extra plumbing because GEM handles belong to the DRM file description they came from. Keep track of both FDs, translate handles between them when needed, and make mixed dma-buf / flink imports still resolve to one internal BO. This follows suggestions from Michel Dänzer, with additional inspiration from iris winsys. Assisted-by: Codex (GPT-5.4) Signed-off-by: Pavel Ondračka Closes: https://gitlab.freedesktop.org/mesa/mesa/-/work_items/11724 --- src/gallium/winsys/radeon/drm/radeon_drm_bo.c | 143 +++++++++++++++--- src/gallium/winsys/radeon/drm/radeon_drm_bo.h | 1 + src/gallium/winsys/radeon/drm/radeon_drm_cs.c | 2 +- .../winsys/radeon/drm/radeon_drm_winsys.c | 111 +++++++++----- .../winsys/radeon/drm/radeon_drm_winsys.h | 3 +- 5 files changed, 198 insertions(+), 62 deletions(-) diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c index 59a35923c4b..a816e9c81a5 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c @@ -45,6 +45,38 @@ radeon_bo_ref_existing(struct radeon_bo *bo) return true; } +/* GEM handles are only valid for the DRM file that created/imported them. + * When internal work uses a render-node FD, KMS/shared exports still need a + * handle for the original app FD, so translate it once and cache the result. + */ +static bool +radeon_bo_get_display_handle(struct radeon_bo *bo, uint32_t *handle) +{ + struct radeon_drm_winsys *ws = bo->rws; + int dma_fd; + + if (ws->fd == ws->ioctl_fd) { + *handle = bo->handle; + return true; + } + + if (!bo->display_handle) { + if (drmPrimeHandleToFD(ws->ioctl_fd, bo->handle, + DRM_CLOEXEC | DRM_RDWR, &dma_fd)) + return false; + + if (drmPrimeFDToHandle(ws->fd, dma_fd, &bo->display_handle)) { + close(dma_fd); + return false; + } + + close(dma_fd); + } + + *handle = bo->display_handle; + return true; +} + struct radeon_bo_va_hole { struct list_head list; uint64_t offset; @@ -56,7 +88,7 @@ static bool radeon_real_bo_is_busy(struct radeon_bo *bo) struct drm_radeon_gem_busy args = {0}; args.handle = bo->handle; - return drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_BUSY, + return drmCommandWriteRead(bo->rws->ioctl_fd, DRM_RADEON_GEM_BUSY, &args, sizeof(args)) != 0; } @@ -89,7 +121,7 @@ static void radeon_real_bo_wait_idle(struct radeon_bo *bo) struct drm_radeon_gem_wait_idle args = {0}; args.handle = bo->handle; - while (drmCommandWrite(bo->rws->fd, DRM_RADEON_GEM_WAIT_IDLE, + while (drmCommandWrite(bo->rws->ioctl_fd, DRM_RADEON_GEM_WAIT_IDLE, &args, sizeof(args)) == -EBUSY); } @@ -175,7 +207,7 @@ static enum radeon_bo_domain radeon_bo_get_initial_domain( args.handle = bo->handle; args.op = RADEON_GEM_OP_GET_INITIAL_DOMAIN; - if (drmCommandWriteRead(bo->rws->fd, DRM_RADEON_GEM_OP, + if (drmCommandWriteRead(bo->rws->ioctl_fd, DRM_RADEON_GEM_OP, &args, sizeof(args))) { fprintf(stderr, "radeon: failed to get initial domain: %p 0x%08X\n", bo, bo->handle); @@ -372,7 +404,7 @@ void radeon_bo_destroy(void *winsys, struct pb_buffer_lean *_buf) RADEON_VM_PAGE_SNOOPED; va.offset = bo->va; - if (drmCommandWriteRead(rws->fd, DRM_RADEON_GEM_VA, &va, + if (drmCommandWriteRead(rws->ioctl_fd, DRM_RADEON_GEM_VA, &va, sizeof(va)) != 0 && va.operation == RADEON_VA_RESULT_ERROR) { fprintf(stderr, "radeon: Failed to deallocate virtual address for buffer:\n"); @@ -388,7 +420,12 @@ void radeon_bo_destroy(void *winsys, struct pb_buffer_lean *_buf) /* Close object. */ args.handle = bo->handle; - drmIoctl(rws->fd, DRM_IOCTL_GEM_CLOSE, &args); + drmIoctl(rws->ioctl_fd, DRM_IOCTL_GEM_CLOSE, &args); + + if (bo->display_handle) { + args.handle = bo->display_handle; + drmIoctl(rws->fd, DRM_IOCTL_GEM_CLOSE, &args); + } mtx_destroy(&bo->u.real.map_mutex); @@ -449,7 +486,7 @@ void *radeon_bo_do_map(struct radeon_bo *bo) args.handle = bo->handle; args.offset = 0; args.size = (uint64_t)bo->base.size; - if (drmCommandWriteRead(bo->rws->fd, + if (drmCommandWriteRead(bo->rws->ioctl_fd, DRM_RADEON_GEM_MMAP, &args, sizeof(args))) { @@ -460,13 +497,13 @@ void *radeon_bo_do_map(struct radeon_bo *bo) } ptr = os_mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, - bo->rws->fd, args.addr_ptr); + bo->rws->ioctl_fd, args.addr_ptr); if (ptr == MAP_FAILED) { /* Clear the cache and try again. */ pb_cache_release_all_buffers(&bo->rws->bo_cache); ptr = os_mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, - bo->rws->fd, args.addr_ptr); + bo->rws->ioctl_fd, args.addr_ptr); if (ptr == MAP_FAILED) { mtx_unlock(&bo->u.real.map_mutex); fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno); @@ -636,7 +673,7 @@ static struct radeon_bo *radeon_create_bo(struct radeon_drm_winsys *rws, if (flags & RADEON_FLAG_NO_CPU_ACCESS) args.flags |= RADEON_GEM_NO_CPU_ACCESS; - if (drmCommandWriteRead(rws->fd, DRM_RADEON_GEM_CREATE, + if (drmCommandWriteRead(rws->ioctl_fd, DRM_RADEON_GEM_CREATE, &args, sizeof(args))) { fprintf(stderr, "radeon: Failed to allocate a buffer:\n"); fprintf(stderr, "radeon: size : %u bytes\n", size); @@ -689,7 +726,7 @@ static struct radeon_bo *radeon_create_bo(struct radeon_drm_winsys *rws, RADEON_VM_PAGE_WRITEABLE | RADEON_VM_PAGE_SNOOPED; va.offset = bo->va; - r = drmCommandWriteRead(rws->fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); + r = drmCommandWriteRead(rws->ioctl_fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); if (r && va.operation == RADEON_VA_RESULT_ERROR) { fprintf(stderr, "radeon: Failed to allocate virtual address for buffer:\n"); fprintf(stderr, "radeon: size : %d bytes\n", size); @@ -866,7 +903,7 @@ static void radeon_bo_get_metadata(struct radeon_winsys *rws, args.handle = bo->handle; - drmCommandWriteRead(bo->rws->fd, + drmCommandWriteRead(bo->rws->ioctl_fd, DRM_RADEON_GEM_GET_TILING, &args, sizeof(args)); @@ -975,7 +1012,7 @@ static void radeon_bo_set_metadata(struct radeon_winsys *rws, args.handle = bo->handle; - drmCommandWriteRead(bo->rws->fd, + drmCommandWriteRead(bo->rws->ioctl_fd, DRM_RADEON_GEM_SET_TILING, &args, sizeof(args)); @@ -1097,7 +1134,7 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_ptr(struct radeon_winsys *rw RADEON_GEM_USERPTR_REGISTER | RADEON_GEM_USERPTR_VALIDATE; - if (drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_USERPTR, + if (drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_GEM_USERPTR, &args, sizeof(args))) { FREE(bo); return NULL; @@ -1136,7 +1173,7 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_ptr(struct radeon_winsys *rw RADEON_VM_PAGE_WRITEABLE | RADEON_VM_PAGE_SNOOPED; va.offset = bo->va; - r = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); + r = drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); if (r && va.operation == RADEON_VA_RESULT_ERROR) { fprintf(stderr, "radeon: Failed to assign virtual address space\n"); radeon_bo_destroy(NULL, &bo->base); @@ -1185,8 +1222,10 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_handle(struct radeon_winsys /* First check if there already is an existing bo for the handle. */ bo = util_hash_table_get(ws->bo_names, (void*)(uintptr_t)whandle->handle); } else if (whandle->type == WINSYS_HANDLE_TYPE_FD) { - /* We must first get the GEM handle, as fds are unreliable keys */ - r = drmPrimeFDToHandle(ws->fd, whandle->handle, &handle); + /* dma-buf FDs are process-local and unsuitable as cache keys. + * Look up the imported BO via its GEM handle on ws->ioctl_fd. + */ + r = drmPrimeFDToHandle(ws->ioctl_fd, whandle->handle, &handle); if (r) goto fail; bo = util_hash_table_get(ws->bo_handles, (void*)(uintptr_t)handle); @@ -1208,8 +1247,9 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_handle(struct radeon_winsys if (whandle->type == WINSYS_HANDLE_TYPE_SHARED) { struct drm_gem_open open_arg = {}; + struct drm_gem_close close_arg = {}; memset(&open_arg, 0, sizeof(open_arg)); - /* Open the BO. */ + /* GEM flink names are tied to the original app FD, so open on ws->fd. */ open_arg.name = whandle->handle; if (drmIoctl(ws->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) { FREE(bo); @@ -1218,6 +1258,55 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_handle(struct radeon_winsys handle = open_arg.handle; size = open_arg.size; bo->flink_name = whandle->handle; + + if (ws->fd != ws->ioctl_fd) { + int dma_fd; + + /* Internal BO tracking and command submission use ws->ioctl_fd. + * When that differs from ws->fd, convert the temporary GEM handle + * from ws->fd into a dma-buf and re-import it on ws->ioctl_fd, so + * bo->handle always names the object on the internal ioctl fd. + */ + if (drmPrimeHandleToFD(ws->fd, open_arg.handle, DRM_CLOEXEC | DRM_RDWR, + &dma_fd)) { + close_arg.handle = open_arg.handle; + drmIoctl(ws->fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + FREE(bo); + goto fail; + } + + r = drmPrimeFDToHandle(ws->ioctl_fd, dma_fd, &handle); + close(dma_fd); + + close_arg.handle = open_arg.handle; + drmIoctl(ws->fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + + if (r) { + FREE(bo); + goto fail; + } + + /* Mixed legacy-name and dma-buf imports of the same object should + * still resolve to a single winsys BO keyed by the ioctl_fd handle. + */ + struct radeon_bo *existing = util_hash_table_get(ws->bo_handles, + (void*)(uintptr_t)handle); + if (existing) { + if (radeon_bo_ref_existing(existing)) { + FREE(bo); + assert(!existing->flink_name || + existing->flink_name == whandle->handle); + if (!existing->flink_name) { + existing->flink_name = whandle->handle; + _mesa_hash_table_insert(ws->bo_names, + (void*)(uintptr_t)existing->flink_name, + existing); + } + bo = existing; + goto done; + } + } + } } else if (whandle->type == WINSYS_HANDLE_TYPE_FD) { size = lseek(whandle->handle, 0, SEEK_END); /* @@ -1233,6 +1322,7 @@ static struct pb_buffer_lean *radeon_winsys_bo_from_handle(struct radeon_winsys assert(handle != 0); + /* bo->handle is always the GEM handle valid on ws->ioctl_fd. */ bo->handle = handle; /* Initialize it. */ @@ -1265,7 +1355,7 @@ done: RADEON_VM_PAGE_WRITEABLE | RADEON_VM_PAGE_SNOOPED; va.offset = bo->va; - r = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); + r = drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_GEM_VA, &va, sizeof(va)); if (r && va.operation == RADEON_VA_RESULT_ERROR) { fprintf(stderr, "radeon: Failed to assign virtual address space\n"); radeon_bo_destroy(NULL, &bo->base); @@ -1317,8 +1407,13 @@ static bool radeon_winsys_bo_get_handle(struct radeon_winsys *rws, bo->u.real.use_reusable_pool = false; if (whandle->type == WINSYS_HANDLE_TYPE_SHARED) { + uint32_t handle; + if (!bo->flink_name) { - flink.handle = bo->handle; + if (!radeon_bo_get_display_handle(bo, &handle)) + return false; + + flink.handle = handle; if (ioctl(ws->fd, DRM_IOCTL_GEM_FLINK, &flink)) { return false; @@ -1332,9 +1427,15 @@ static bool radeon_winsys_bo_get_handle(struct radeon_winsys *rws, } whandle->handle = bo->flink_name; } else if (whandle->type == WINSYS_HANDLE_TYPE_KMS) { - whandle->handle = bo->handle; + uint32_t handle; + + if (!radeon_bo_get_display_handle(bo, &handle)) + return false; + + whandle->handle = handle; } else if (whandle->type == WINSYS_HANDLE_TYPE_FD) { - if (drmPrimeHandleToFD(ws->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, (int*)&whandle->handle)) + if (drmPrimeHandleToFD(ws->ioctl_fd, bo->handle, + DRM_CLOEXEC | DRM_RDWR, (int*)&whandle->handle)) return false; } diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h index 5f4553edc42..9f909981c79 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h @@ -37,6 +37,7 @@ struct radeon_bo { void *user_ptr; /* from buffer_from_ptr */ uint32_t handle; /* 0 for slab entries */ + uint32_t display_handle; /* GEM handle valid for rws->fd when it differs. */ uint32_t flink_name; uint64_t va; uint32_t hash; diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c index 22e604fe8f2..fb3704a4e88 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c @@ -110,7 +110,7 @@ static bool radeon_init_cs_context(struct radeon_cs_context *csc, { int i; - csc->fd = ws->fd; + csc->fd = ws->ioctl_fd; csc->chunks[0].chunk_id = RADEON_CHUNK_ID_IB; csc->chunks[0].length_dw = 0; diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c index e748eab22f9..f8180068030 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,24 @@ static struct hash_table *fd_tab = NULL; static simple_mtx_t fd_tab_mutex = SIMPLE_MTX_INITIALIZER; +static int +radeon_open_render_node(int fd) +{ + char *render_device; + int render_fd = -1; + + if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) + return -1; + + render_device = drmGetRenderDeviceNameFromFd(fd); + if (!render_device) + return -1; + + render_fd = open(render_device, O_RDWR | O_CLOEXEC); + free(render_device); + return render_fd; +} + /* Enable/disable feature access for one command stream. * If enable == true, return true on success. * Otherwise, return false. @@ -66,7 +85,7 @@ static bool radeon_set_fd_access(struct radeon_drm_cs *applier, /* Pass through the request to the kernel. */ info.value = (unsigned long)&value; info.request = request; - if (drmCommandWriteRead(applier->ws->fd, DRM_RADEON_INFO, + if (drmCommandWriteRead(applier->ws->ioctl_fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0) { mtx_unlock(&*mutex); return false; @@ -87,7 +106,7 @@ static bool radeon_set_fd_access(struct radeon_drm_cs *applier, return false; } -static bool radeon_get_drm_value(int fd, unsigned request, +static bool radeon_get_drm_value(struct radeon_drm_winsys *ws, unsigned request, const char *errname, uint32_t *out) { struct drm_radeon_info info; @@ -98,7 +117,7 @@ static bool radeon_get_drm_value(int fd, unsigned request, info.value = (unsigned long)out; info.request = request; - retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); + retval = drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_INFO, &info, sizeof(info)); if (retval) { if (errname) { fprintf(stderr, "radeon: Failed to get %s, error number %d\n", @@ -204,7 +223,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) */ /* Get DRM version. */ - version = drmGetVersion(ws->fd); + version = drmGetVersion(ws->ioctl_fd); if (!version) return false; @@ -227,7 +246,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) drmFreeVersion(version); /* Get PCI ID. */ - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_DEVICE_ID, "PCI ID", + if (!radeon_get_drm_value(ws, RADEON_INFO_DEVICE_ID, "PCI ID", &ws->info.pci_id)) return false; @@ -371,16 +390,16 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) ws->info.vce_fw_version = 0x00000000; uint32_t value = RADEON_CS_RING_UVD; - if (radeon_get_drm_value(ws->fd, RADEON_INFO_RING_WORKING, + if (radeon_get_drm_value(ws, RADEON_INFO_RING_WORKING, "UVD Ring working", &value)) { ws->info.ip[AMD_IP_UVD].num_queues = 1; } value = RADEON_CS_RING_VCE; - if (radeon_get_drm_value(ws->fd, RADEON_INFO_RING_WORKING, + if (radeon_get_drm_value(ws, RADEON_INFO_RING_WORKING, NULL, &value) && value) { - if (radeon_get_drm_value(ws->fd, RADEON_INFO_VCE_FW_VERSION, + if (radeon_get_drm_value(ws, RADEON_INFO_VCE_FW_VERSION, "VCE FW version", &value)) { ws->info.vce_fw_version = value; ws->info.ip[AMD_IP_VCE].num_queues = 1; @@ -398,12 +417,12 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) * aren't set. */ ws->info.has_userptr = - drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_USERPTR, + drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_GEM_USERPTR, &args, sizeof(args)) == -EACCES; } /* Get GEM info. */ - retval = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_INFO, + retval = drmCommandWriteRead(ws->ioctl_fd, DRM_RADEON_GEM_INFO, &gem_info, sizeof(gem_info)); if (retval) { fprintf(stderr, "radeon: Failed to get MM info, error number %d\n", @@ -427,7 +446,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) ws->info.max_heap_size_kb = MIN2(ws->info.max_heap_size_kb, 4 * 1024 * 1024); /* 4 GB */ /* Get max clock frequency info and convert it to MHz */ - radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SCLK, NULL, + radeon_get_drm_value(ws, RADEON_INFO_MAX_SCLK, NULL, &ws->info.max_gpu_freq_mhz); ws->info.max_gpu_freq_mhz /= 1000; @@ -435,12 +454,12 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) /* Generation-specific queries. */ if (ws->gen == DRV_R300) { - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_GB_PIPES, + if (!radeon_get_drm_value(ws, RADEON_INFO_NUM_GB_PIPES, "GB pipe count", &ws->info.r300_num_gb_pipes)) return false; - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_Z_PIPES, + if (!radeon_get_drm_value(ws, RADEON_INFO_NUM_Z_PIPES, "Z pipe count", &ws->info.r300_num_z_pipes)) return false; @@ -448,16 +467,16 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) else if (ws->gen >= DRV_R600) { uint32_t tiling_config = 0; - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_BACKENDS, + if (!radeon_get_drm_value(ws, RADEON_INFO_NUM_BACKENDS, "num backends", &ws->info.max_render_backends)) return false; /* get the GPU counter frequency, failure is not fatal */ - radeon_get_drm_value(ws->fd, RADEON_INFO_CLOCK_CRYSTAL_FREQ, NULL, + radeon_get_drm_value(ws, RADEON_INFO_CLOCK_CRYSTAL_FREQ, NULL, &ws->info.clock_crystal_freq); - radeon_get_drm_value(ws->fd, RADEON_INFO_TILING_CONFIG, NULL, + radeon_get_drm_value(ws, RADEON_INFO_TILING_CONFIG, NULL, &tiling_config); ws->info.r600_num_banks = @@ -474,7 +493,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) ws->info.r600_pipe_interleave_bytes = ws->info.gfx_level >= EVERGREEN ? 512 : 256; - radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_TILE_PIPES, NULL, + radeon_get_drm_value(ws, RADEON_INFO_NUM_TILE_PIPES, NULL, &ws->info.num_tile_pipes); /* "num_tiles_pipes" must be equal to the number of pipes (Px) in the @@ -485,7 +504,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) if (ws->gen == DRV_SI && ws->info.num_tile_pipes == 12) ws->info.num_tile_pipes = 8; - if (radeon_get_drm_value(ws->fd, RADEON_INFO_BACKEND_MAP, NULL, + if (radeon_get_drm_value(ws, RADEON_INFO_BACKEND_MAP, NULL, &ws->info.r600_gb_backend_map)) ws->info.r600_gb_backend_map_valid = true; @@ -498,7 +517,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) if (ws->gen >= DRV_SI) { uint32_t mask; - radeon_get_drm_value(ws->fd, RADEON_INFO_SI_BACKEND_ENABLED_MASK, NULL, &mask); + radeon_get_drm_value(ws, RADEON_INFO_SI_BACKEND_ENABLED_MASK, NULL, &mask); ws->info.enabled_rb_mask = mask; } @@ -507,13 +526,13 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) uint32_t ib_vm_max_size; ws->info.r600_has_virtual_memory = true; - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_VA_START, NULL, + if (!radeon_get_drm_value(ws, RADEON_INFO_VA_START, NULL, &ws->va_start)) ws->info.r600_has_virtual_memory = false; - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_IB_VM_MAX_SIZE, NULL, + if (!radeon_get_drm_value(ws, RADEON_INFO_IB_VM_MAX_SIZE, NULL, &ib_vm_max_size)) ws->info.r600_has_virtual_memory = false; - radeon_get_drm_value(ws->fd, RADEON_INFO_VA_UNMAP_WORKING, NULL, + radeon_get_drm_value(ws, RADEON_INFO_VA_UNMAP_WORKING, NULL, &ws->va_unmap_working); if (ws->gen == DRV_R600 && !debug_get_bool_option("RADEON_VA", false)) @@ -523,15 +542,15 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) /* Get max pipes, this is only needed for compute shaders. All evergreen+ * chips have at least 2 pipes, so we use 2 as a default. */ ws->info.r600_max_quad_pipes = 2; - radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_PIPES, NULL, + radeon_get_drm_value(ws, RADEON_INFO_MAX_PIPES, NULL, &ws->info.r600_max_quad_pipes); /* All GPUs have at least one compute unit */ ws->info.num_cu = 1; - radeon_get_drm_value(ws->fd, RADEON_INFO_ACTIVE_CU_COUNT, NULL, + radeon_get_drm_value(ws, RADEON_INFO_ACTIVE_CU_COUNT, NULL, &ws->info.num_cu); - radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SE, NULL, + radeon_get_drm_value(ws, RADEON_INFO_MAX_SE, NULL, &ws->info.max_se); switch (ws->info.family) { @@ -581,7 +600,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) ws->info.num_se = ws->info.max_se; - radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SH_PER_SE, NULL, + radeon_get_drm_value(ws, RADEON_INFO_MAX_SH_PER_SE, NULL, &ws->info.max_sa_per_se); if (ws->gen == DRV_SI) { ws->info.max_good_cu_per_sa = @@ -589,7 +608,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) (ws->info.max_se * ws->info.max_sa_per_se); } - radeon_get_drm_value(ws->fd, RADEON_INFO_ACCEL_WORKING2, NULL, + radeon_get_drm_value(ws, RADEON_INFO_ACCEL_WORKING2, NULL, &ws->accel_working2); if (ws->info.family == CHIP_HAWAII && ws->accel_working2 < 2) { fprintf(stderr, "radeon: GPU acceleration for Hawaii disabled, " @@ -600,7 +619,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) } if (ws->info.gfx_level == GFX7) { - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_CIK_MACROTILE_MODE_ARRAY, NULL, + if (!radeon_get_drm_value(ws, RADEON_INFO_CIK_MACROTILE_MODE_ARRAY, NULL, ws->info.cik_macrotile_mode_array)) { fprintf(stderr, "radeon: Kernel 3.13 is required for Sea Islands support.\n"); return false; @@ -608,7 +627,7 @@ static bool do_winsys_init(struct radeon_drm_winsys *ws) } if (ws->info.gfx_level >= GFX6) { - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, NULL, + if (!radeon_get_drm_value(ws, RADEON_INFO_SI_TILE_MODE_ARRAY, NULL, ws->info.si_tile_mode_array)) { fprintf(stderr, "radeon: Kernel 3.10 is required for Southern Islands support.\n"); return false; @@ -738,6 +757,8 @@ static void radeon_winsys_destroy(struct radeon_winsys *rws) mtx_destroy(&ws->vm64.mutex); mtx_destroy(&ws->bo_fence_lock); + if (ws->ioctl_fd >= 0 && ws->ioctl_fd != ws->fd) + close(ws->ioctl_fd); if (ws->fd >= 0) close(ws->fd); @@ -775,7 +796,7 @@ uint32_t radeon_drm_get_gpu_reset_counter(struct radeon_drm_winsys *ws) { uint64_t retval = 0; - radeon_get_drm_value(ws->fd, RADEON_INFO_GPU_RESET_COUNTER, + radeon_get_drm_value(ws, RADEON_INFO_GPU_RESET_COUNTER, "gpu-reset-counter", (uint32_t*)&retval); return retval; } @@ -805,7 +826,7 @@ static uint64_t radeon_query_value(struct radeon_winsys *rws, return 0; } - radeon_get_drm_value(ws->fd, RADEON_INFO_TIMESTAMP, "timestamp", + radeon_get_drm_value(ws, RADEON_INFO_TIMESTAMP, "timestamp", (uint32_t*)&retval); return retval; case RADEON_NUM_GFX_IBS: @@ -813,7 +834,7 @@ static uint64_t radeon_query_value(struct radeon_winsys *rws, case RADEON_NUM_SDMA_IBS: return ws->num_sdma_IBs; case RADEON_NUM_BYTES_MOVED: - radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_BYTES_MOVED, + radeon_get_drm_value(ws, RADEON_INFO_NUM_BYTES_MOVED, "num-bytes-moved", (uint32_t*)&retval); return retval; case RADEON_NUM_EVICTIONS: @@ -825,23 +846,23 @@ static uint64_t radeon_query_value(struct radeon_winsys *rws, case RADEON_SLAB_WASTED_GTT: return 0; /* unimplemented */ case RADEON_VRAM_USAGE: - radeon_get_drm_value(ws->fd, RADEON_INFO_VRAM_USAGE, + radeon_get_drm_value(ws, RADEON_INFO_VRAM_USAGE, "vram-usage", (uint32_t*)&retval); return retval; case RADEON_GTT_USAGE: - radeon_get_drm_value(ws->fd, RADEON_INFO_GTT_USAGE, + radeon_get_drm_value(ws, RADEON_INFO_GTT_USAGE, "gtt-usage", (uint32_t*)&retval); return retval; case RADEON_GPU_TEMPERATURE: - radeon_get_drm_value(ws->fd, RADEON_INFO_CURRENT_GPU_TEMP, + radeon_get_drm_value(ws, RADEON_INFO_CURRENT_GPU_TEMP, "gpu-temp", (uint32_t*)&retval); return retval; case RADEON_CURRENT_SCLK: - radeon_get_drm_value(ws->fd, RADEON_INFO_CURRENT_GPU_SCLK, + radeon_get_drm_value(ws, RADEON_INFO_CURRENT_GPU_SCLK, "current-gpu-sclk", (uint32_t*)&retval); return retval; case RADEON_CURRENT_MCLK: - radeon_get_drm_value(ws->fd, RADEON_INFO_CURRENT_GPU_MCLK, + radeon_get_drm_value(ws, RADEON_INFO_CURRENT_GPU_MCLK, "current-gpu-mclk", (uint32_t*)&retval); return retval; case RADEON_CS_THREAD_TIME: @@ -860,7 +881,7 @@ static bool radeon_read_registers(struct radeon_winsys *rws, for (i = 0; i < num_registers; i++) { uint32_t reg = reg_offset + i*4; - if (!radeon_get_drm_value(ws->fd, RADEON_INFO_READ_REG, NULL, ®)) + if (!radeon_get_drm_value(ws, RADEON_INFO_READ_REG, NULL, ®)) return false; out[i] = reg; } @@ -946,7 +967,17 @@ radeon_drm_winsys_create(int fd, const struct pipe_screen_config *config, return NULL; } + ws->fd = -1; + ws->ioctl_fd = -1; ws->fd = os_dupfd_cloexec(fd); + if (ws->fd < 0) + goto fail1; + + ws->ioctl_fd = ws->fd; + + int render_fd = radeon_open_render_node(ws->fd); + if (render_fd >= 0) + ws->ioctl_fd = render_fd; if (!do_winsys_init(ws)) goto fail1; @@ -979,7 +1010,7 @@ radeon_drm_winsys_create(int fd, const struct pipe_screen_config *config, } if (ws->gen >= DRV_R600) { - ws->surf_man = radeon_surface_manager_new(ws->fd); + ws->surf_man = radeon_surface_manager_new(ws->ioctl_fd); if (!ws->surf_man) goto fail_slab; } @@ -1075,6 +1106,8 @@ fail1: simple_mtx_unlock(&fd_tab_mutex); if (ws->surf_man) radeon_surface_manager_free(ws->surf_man); + if (ws->ioctl_fd >= 0 && ws->ioctl_fd != ws->fd) + close(ws->ioctl_fd); if (ws->fd >= 0) close(ws->fd); diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h index 01f0bb5dd2b..fcd5dcffe3f 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h @@ -38,7 +38,8 @@ struct radeon_drm_winsys { struct pb_cache bo_cache; struct pb_slabs bo_slabs; - int fd; /* DRM file descriptor */ + int fd; /* Application-facing DRM file descriptor. */ + int ioctl_fd; /* Render-capable DRM file descriptor for GEM and CS ioctls. */ int num_cs; /* The number of command streams created. */ uint64_t allocated_vram; uint64_t allocated_gtt;