int mgaFlushDMA( int fd, drmLockFlags flags ) { drm_lock_t lock; int ret, i = 0; memset( &lock, 0, sizeof(lock) ); lock.flags = flags & (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL); do { ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); if ( ret == 0 ) return 0; if ( errno != EBUSY ) return -errno; if ( lock.flags & DRM_LOCK_QUIESCENT ) { /* Only keep trying if we need quiescence. */ lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL); do { ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); } if ( ret == 0 ) { return 0; } else { return -errno; } }
void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n, const GLint x[], const GLint y[] ) { drm_clip_rect_t *pbox = rmesa->pClipRects; drm_r128_depth_t d; int nbox = rmesa->numClipRects; int fd = rmesa->driScreen->fd; int i; if ( !nbox || !n ) { return; } if ( nbox >= R128_NR_SAREA_CLIPRECTS ) { rmesa->dirty |= R128_UPLOAD_CLIPRECTS; } if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) { if ( nbox < 3 ) { rmesa->sarea->nbox = 0; } else { rmesa->sarea->nbox = nbox; } d.func = R128_READ_PIXELS; d.n = n; d.x = (int*)&x; d.y = (int*)&y; d.buffer = NULL; d.mask = NULL; drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d)); } else { for (i = 0 ; i < nbox ; ) { int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); drm_clip_rect_t *b = rmesa->sarea->boxes; rmesa->sarea->nbox = nr - i; for ( ; i < nr ; i++) { *b++ = pbox[i]; } rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; d.func = R128_READ_PIXELS; d.n = n; d.x = (int*)&x; d.y = (int*)&y; d.buffer = NULL; d.mask = NULL; drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d)); } } rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; }
void VIAFreeLinear(VIAMemPtr mem) { DEBUG(ErrorF("Freed %lu (pool %d)\n", mem->base, mem->pool)); switch (mem->pool) { case 0: return; case 1: { VIAPtr pVia = VIAPTR(mem->pScrn); if (pVia->useEXA && !pVia->NoAccel) { exaOffscreenFree(mem->pScrn->pScreen, mem->exa); mem->linear = NULL; mem->pool = 0; return; } } xf86FreeOffscreenLinear(mem->linear); mem->linear = NULL; mem->pool = 0; return; case 2: #ifdef XF86DRI if (drmCommandWrite(mem->drm_fd, DRM_VIA_FREEMEM, &mem->drm, sizeof(drm_via_mem_t)) < 0) ErrorF("DRM module failed free.\n"); #endif mem->pool = 0; return; } }
int amdgpu_query_firmware_version(amdgpu_device_handle dev, unsigned fw_type, unsigned ip_instance, unsigned index, uint32_t *version, uint32_t *feature) { struct drm_amdgpu_info request; struct drm_amdgpu_info_firmware firmware = {}; int r; memset(&request, 0, sizeof(request)); request.return_pointer = (uintptr_t)&firmware; request.return_size = sizeof(firmware); request.query = AMDGPU_INFO_FW_VERSION; request.query_fw.fw_type = fw_type; request.query_fw.ip_instance = ip_instance; request.query_fw.index = index; r = drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, sizeof(struct drm_amdgpu_info)); if (r) return r; *version = firmware.ver; *feature = firmware.feature; return 0; }
void i830WaitAge( i830ContextPtr imesa, int age ) { int i = 0; if (GET_DISPATCH_AGE(imesa) >= age) return; while (1) { drmCommandNone(imesa->driFd, DRM_I830_GETAGE); if (GET_DISPATCH_AGE(imesa) >= age) return; imesa->perf_boxes |= I830_BOX_WAIT; if (imesa->do_irqs) { drmI830IrqEmit ie; drmI830IrqWait iw; int ret; ie.irq_seq = &iw.irq_seq; LOCK_HARDWARE( imesa ); ret = drmCommandWriteRead( imesa->driFd, DRM_I830_IRQ_EMIT, &ie, sizeof(ie) ); if ( ret ) { fprintf( stderr, "%s: drmI830IrqEmit: %d\n", __FUNCTION__, ret ); exit(1); } UNLOCK_HARDWARE(imesa); ret = drmCommandWrite( imesa->driFd, DRM_I830_IRQ_WAIT, &iw, sizeof(iw) ); if ( ret ) { fprintf( stderr, "%s: drmI830IrqWait: %d\n", __FUNCTION__, ret ); exit(1); } } else { if (++i > 5000) usleep(1); } } }
int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms) { struct etna_device *dev = pipe->gpu->dev; int ret; struct drm_etnaviv_wait_fence req = { .pipe = pipe->gpu->core, .fence = timestamp, }; if (ms == 0) req.flags |= ETNA_WAIT_NONBLOCK; get_abs_timeout(&req.timeout, ms); ret = drmCommandWrite(dev->fd, DRM_ETNAVIV_WAIT_FENCE, &req, sizeof(req)); if (ret) { ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); return ret; } return 0; } void etna_pipe_del(struct etna_pipe *pipe) { free(pipe); }
void nouveau_channel_free(struct nouveau_channel **chan) { struct nouveau_channel_priv *nvchan; struct nouveau_device_priv *nvdev; struct drm_nouveau_channel_free cf; if (!chan || !*chan) return; nvchan = nouveau_channel(*chan); *chan = NULL; nvdev = nouveau_device(nvchan->base.device); FIRE_RING(&nvchan->base); nouveau_bo_unmap(nvchan->notifier_bo); nouveau_bo_ref(NULL, &nvchan->notifier_bo); nouveau_grobj_free(&nvchan->base.vram); nouveau_grobj_free(&nvchan->base.gart); nouveau_grobj_free(&nvchan->base.nullobj); cf.channel = nvchan->drm.channel; drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf)); free(nvchan); }
void nouveau_channel_free(struct nouveau_channel **chan) { struct nouveau_channel_priv *nvchan; struct nouveau_device_priv *nvdev; struct drm_nouveau_channel_free cf; unsigned i; if (!chan || !*chan) return; nvchan = nouveau_channel(*chan); (*chan)->flush_notify = NULL; *chan = NULL; nvdev = nouveau_device(nvchan->base.device); FIRE_RING(&nvchan->base); nouveau_pushbuf_fini(&nvchan->base); if (nvchan->notifier_bo) { nouveau_bo_unmap(nvchan->notifier_bo); nouveau_bo_ref(NULL, &nvchan->notifier_bo); } for (i = 0; i < nvchan->drm.nr_subchan; i++) free(nvchan->base.subc[i].gr); nouveau_grobj_free(&nvchan->base.vram); nouveau_grobj_free(&nvchan->base.gart); nouveau_grobj_free(&nvchan->base.nullobj); cf.channel = nvchan->drm.channel; drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf)); free(nvchan); }
static void mga_iload_dma_ioctl(mgaContextPtr mmesa, unsigned long dest, int length) { drmBufPtr buf = mmesa->iload_buffer; drmMGAIload iload; int ret, i; if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n", buf->idx, (int) dest, length); iload.idx = buf->idx; iload.dstorg = dest; iload.length = length; i = 0; do { ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD, &iload, sizeof(drmMGAIload) ); } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY ); if ( ret < 0 ) { printf("send iload retcode = %d\n", ret); exit(1); } mmesa->iload_buffer = 0; if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) fprintf(stderr, "finished iload dma put\n"); }
void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer, GLint offset, GLint pitch, GLint format, GLint x, GLint y, GLint width, GLint height ) { drm_r128_blit_t blit; GLint ret; blit.idx = buffer->idx; blit.offset = offset; blit.pitch = pitch; blit.format = format; blit.x = x; blit.y = y; blit.width = width; blit.height = height; ret = drmCommandWrite( rmesa->driFd, DRM_R128_BLIT, &blit, sizeof(blit) ); if ( ret ) { UNLOCK_HARDWARE( rmesa ); fprintf( stderr, "DRM_R128_BLIT: return = %d\n", ret ); exit( 1 ); } }
/* Called via glXFreeMemoryMESA() */ void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer) { GET_CURRENT_CONTEXT(ctx); r200ContextPtr rmesa; ptrdiff_t region_offset; drm_radeon_mem_free_t memfree; int ret; if (R200_DEBUG & RADEON_IOCTL) fprintf(stderr, "%s %p\n", __FUNCTION__, pointer); if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->radeon.radeonScreen->gartTextures.map) { fprintf(stderr, "%s: no context\n", __FUNCTION__); return; } region_offset = (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map; if (region_offset < 0 || region_offset > rmesa->radeon.radeonScreen->gartTextures.size) { fprintf(stderr, "offset %d outside range 0..%d\n", region_offset, rmesa->radeon.radeonScreen->gartTextures.size); return; } memfree.region = RADEON_MEM_REGION_GART; memfree.region_offset = region_offset; ret = drmCommandWrite( rmesa->radeon.radeonScreen->driScreen->fd, DRM_RADEON_FREE, &memfree, sizeof(memfree)); if (ret) fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret); }
void intelFreeAGP( intelContextPtr intel, void *pointer ) { int region_offset; drmI830MemFree memfree; int ret; region_offset = (char *)pointer - (char *)intel->intelScreen->tex.map; if (region_offset < 0 || region_offset > intel->intelScreen->tex.size) { fprintf(stderr, "offset %d outside range 0..%d\n", region_offset, intel->intelScreen->tex.size); return; } memfree.region = I830_MEM_REGION_AGP; memfree.region_offset = region_offset; ret = drmCommandWrite( intel->driFd, DRM_I830_FREE, &memfree, sizeof(memfree)); if (ret) fprintf(stderr, "%s: DRM_I830_FREE ret %d\n", __FUNCTION__, ret); }
unsigned long long getvram() { int ret = -1; unsigned long long val = 0; if (strcmp(drm_name, "radeon") == 0) { struct drm_radeon_info info; memset(&info, 0, sizeof(info)); info.value = (unsigned long) &val; info.request = RADEON_INFO_VRAM_USAGE; ret = drmCommandWriteRead(drm_fd, DRM_RADEON_INFO, &info, sizeof(info)); } else if (strcmp(drm_name, "amdgpu") == 0) { #ifdef ENABLE_AMDGPU struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (unsigned long) &val; request.return_size = sizeof(val); request.query = AMDGPU_INFO_VRAM_USAGE; ret = drmCommandWrite(drm_fd, DRM_AMDGPU_INFO, &request, sizeof(request)); #endif } if (ret) return 0; return val; }
void intelWaitIrq(struct intel_context *intel, int seq) { struct drm_i915_irq_wait iw; int ret, lastdispatch; volatile struct drm_i915_sarea *sarea = intel->sarea; if (intel->no_hw) return; DBG("%s %d\n", __FUNCTION__, seq); iw.irq_seq = seq; do { lastdispatch = sarea->last_dispatch; ret = drmCommandWrite(intel->driFd, DRM_I915_IRQ_WAIT, &iw, sizeof(iw)); } while (ret == -EAGAIN || ret == -EINTR || (ret == -EBUSY && lastdispatch != sarea->last_dispatch) || (ret == 0 && seq > sarea->last_dispatch) || (ret == 0 && sarea->last_dispatch - seq >= (1 << 24))); if (ret) { fprintf(stderr, "%s: drm_i915_irq_wait: %d\n", __FUNCTION__, ret); exit(1); } }
int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value) { struct drm_omap_param req = { .param = param, .value = value, }; return drmCommandWrite(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req)); }
boolean vmw_ioctl_init(struct vmw_winsys_screen *vws) { struct drm_vmw_getparam_arg gp_arg; struct drm_vmw_get_3d_cap_arg cap_arg; unsigned int size; int ret; VMW_FUNC; memset(&gp_arg, 0, sizeof(gp_arg)); gp_arg.param = DRM_VMW_PARAM_3D; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM, &gp_arg, sizeof(gp_arg)); if (ret || gp_arg.value == 0) { vmw_error("No 3D enabled (%i, %s).\n", ret, strerror(-ret)); goto out_no_3d; } memset(&gp_arg, 0, sizeof(gp_arg)); gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM, &gp_arg, sizeof(gp_arg)); if (ret) { vmw_error("Failed to get fifo hw version (%i, %s).\n", ret, strerror(-ret)); goto out_no_3d; } vws->ioctl.hwversion = gp_arg.value; size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t); vws->ioctl.buffer = calloc(1, size); if (!vws->ioctl.buffer) { debug_printf("Failed alloc fifo 3D caps buffer.\n"); goto out_no_3d; } memset(&cap_arg, 0, sizeof(cap_arg)); cap_arg.buffer = (uint64_t) (unsigned long) (vws->ioctl.buffer); cap_arg.max_size = size; ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP, &cap_arg, sizeof(cap_arg)); if (ret) { debug_printf("Failed to get 3D capabilities" " (%i, %s).\n", ret, strerror(-ret)); goto out_no_caps; } vmw_printf("%s OK\n", __FUNCTION__); return TRUE; out_no_caps: free(vws->ioctl.buffer); out_no_3d: debug_printf("%s Failed\n", __FUNCTION__); return FALSE; }
Bool I810InitDma(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); I810RingBuffer *ring = pI810->LpRing; I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate; drmI810Init info; memset(&info, 0, sizeof(drmI810Init)); info.ring_start = ring->mem.Start; info.ring_end = ring->mem.End; info.ring_size = ring->mem.Size; info.mmio_offset = (unsigned int)pI810DRI->regs; info.buffers_offset = (unsigned int)pI810->buffer_map; info.sarea_priv_offset = sizeof(XF86DRISAREARec); info.front_offset = 0; info.back_offset = pI810->BackBuffer.Start; info.depth_offset = pI810->DepthBuffer.Start; info.overlay_offset = pI810->OverlayStart; info.overlay_physical = pI810->OverlayPhysical; info.w = pScrn->virtualX; info.h = pScrn->virtualY; info.pitch = pI810->auxPitch; info.pitch_bits = pI810->auxPitchBits; /* We require DRM v1.2 or greater. Since DRM v1.2 broke compatibility * we created a new v1.4 that supports a new init function. Eventually the * old init function will go away. If you change the drm interface, make a * new init type too so that we can detect the new client. */ switch(i810_drm_version) { case ((1<<16) | 0): case ((1<<16) | 1): case ((1<<16) | 2): case ((1<<16) | 3): /* Use OLD drm < 1.4 init */ info.func = I810_INIT_DMA; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init PRE v1.4 interface.\n"); break; default: case ((1<<16) | 4): /* DRM version 1.3 or greater init */ info.func = I810_INIT_DMA_1_4; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init v1.4 interface.\n"); break; } if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT, &info, sizeof(drmI810Init))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] I810 Dma Initialization failed.\n"); return FALSE; } return TRUE; }
static int set_memtype(struct fd_device *dev, uint32_t handle, uint32_t flags) { struct drm_kgsl_gem_memtype req = { .handle = handle, .type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK, }; return drmCommandWrite(dev->fd, DRM_KGSL_GEM_SETMEMTYPE, &req, sizeof(req)); }
static int R128CCEStop(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; drm_r128_cce_stop_t stop; int ret, i; stop.flush = 1; stop.idle = 1; ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) ); if ( ret == 0 ) { return 0; } else if ( errno != EBUSY ) { return -errno; } stop.flush = 0; i = 0; do { ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) ); } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); if ( ret == 0 ) { return 0; } else if ( errno != EBUSY ) { return -errno; } stop.idle = 0; if ( drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) )) { return -errno; } else { return 0; } }
void mgaReleaseBufLocked( mgaContextPtr mmesa, drmBufPtr buffer ) { drmMGAVertex vertex; if (!buffer) return; vertex.idx = buffer->idx; vertex.used = 0; vertex.discard = 1; drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, &vertex, sizeof(drmMGAVertex) ); }
/* The screen is being closed, so clean up any state and free any resources used by the DRI. */ void R128DRICloseScreen(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; drm_r128_init_t drmInfo; /* Stop the CCE if it is still in use */ R128CCE_STOP(ctx, info); if (info->irq) { drmCtlUninstHandler(ctx->drmFD); info->irq = 0; } /* De-allocate vertex buffers */ if (info->buffers) { drmUnmapBufs(info->buffers); info->buffers = NULL; } /* De-allocate all kernel resources */ memset(&drmInfo, 0, sizeof(drmInfo)); drmInfo.func = R128_CLEANUP_CCE; drmCommandWrite(ctx->drmFD, DRM_R128_INIT, &drmInfo, sizeof(drmInfo)); /* De-allocate all AGP resources */ if (info->agpTex) { drmUnmap(info->agpTex, info->agpTexMapSize); info->agpTex = NULL; } if (info->buf) { drmUnmap(info->buf, info->bufMapSize); info->buf = NULL; } if (info->ringReadPtr) { drmUnmap(info->ringReadPtr, info->ringReadMapSize); info->ringReadPtr = NULL; } if (info->ring) { drmUnmap(info->ring, info->ringMapSize); info->ring = NULL; } if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { drmAgpUnbind(ctx->drmFD, info->agpMemHandle); drmAgpFree(ctx->drmFD, info->agpMemHandle); info->agpMemHandle = 0; drmAgpRelease(ctx->drmFD); } if (info->pciMemHandle) { drmScatterGatherFree(ctx->drmFD, info->pciMemHandle); info->pciMemHandle = 0; } }
int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id, unsigned size, void *value) { struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (uintptr_t)value; request.return_size = size; request.query = info_id; return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, sizeof(struct drm_amdgpu_info)); }
/* Wrapper for DRM_NOUVEAU_GETPARAM ioctl */ GLboolean nouveauDRMSetParam(nouveauContextPtr nmesa, unsigned int param, uint64_t value) { drm_nouveau_setparam_t setp; setp.param = param; setp.value = value; if (drmCommandWrite(nmesa->driFd, DRM_NOUVEAU_SETPARAM, &setp, sizeof(setp))) return GL_FALSE; return GL_TRUE; }
void vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid) { struct drm_vmw_surface_arg s_arg; VMW_FUNC; memset(&s_arg, 0, sizeof(s_arg)); s_arg.sid = sid; (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE, &s_arg, sizeof(s_arg)); }
static int bo_wait(struct radeon_bo_int *boi) { struct drm_radeon_gem_wait_idle args; int ret; /* Zero out args to make valgrind happy */ memset(&args, 0, sizeof(args)); args.handle = boi->handle; do { ret = drmCommandWrite(boi->bom->fd, DRM_RADEON_GEM_WAIT_IDLE, &args, sizeof(args)); } while (ret == -EBUSY); return ret; }
static void r200WaitIrq( r200ContextPtr rmesa ) { int ret; do { ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_IRQ_WAIT, &rmesa->iw, sizeof(rmesa->iw) ); } while (ret && (errno == EINTR || errno == EAGAIN)); if ( ret ) { fprintf( stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, ret ); exit(1); } }
void vmw_ioctl_shader_destroy(struct vmw_winsys_screen *vws, uint32 shid) { struct drm_vmw_shader_arg sh_arg; VMW_FUNC; memset(&sh_arg, 0, sizeof(sh_arg)); sh_arg.handle = shid; (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SHADER, &sh_arg, sizeof(sh_arg)); }
void vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid) { struct drm_vmw_context_arg c_arg; VMW_FUNC; memset(&c_arg, 0, sizeof(c_arg)); c_arg.cid = cid; (void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT, &c_arg, sizeof(c_arg)); }
int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id, int32_t *result) { struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (uintptr_t)result; request.return_size = sizeof(*result); request.query = AMDGPU_INFO_CRTC_FROM_ID; request.mode_crtc.id = id; return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, sizeof(struct drm_amdgpu_info)); }
int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, unsigned type, uint32_t *count) { struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (uintptr_t)count; request.return_size = sizeof(*count); request.query = AMDGPU_INFO_HW_IP_COUNT; request.query_hw_ip.type = type; return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, sizeof(struct drm_amdgpu_info)); }