From: Keith Packard <keithp@xxxxxxxxxx> Signed-off-by: Keith Packard <keithp at keithp.com> (Ported from xserver commit e4e3447603b5fd3a38a92c3f972396d1f81168ad) Signed-off-by: Michel Dänzer <michel.daenzer at amd.com> --- configure.ac | 2 +- src/amdgpu_kms.c | 1 + src/drmmode_display.c | 159 +++++++++++++++++++++++++++++++++++++++++- src/drmmode_display.h | 6 ++ 4 files changed, 166 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a475f3713..f4633e370 100644 --- a/configure.ac +++ b/configure.ac @@ -70,7 +70,7 @@ XORG_DRIVER_CHECK_EXT(XV, videoproto) XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto) # Checks for libraries. -PKG_CHECK_MODULES(LIBDRM, [libdrm >= 2.4.78]) +PKG_CHECK_MODULES(LIBDRM, [libdrm >= 2.4.89]) PKG_CHECK_MODULES(LIBDRM_AMDGPU, [libdrm_amdgpu >= 2.4.76]) PKG_CHECK_MODULES(GBM, [gbm]) diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index bedd02037..c357ab6b7 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -1703,6 +1703,7 @@ static Bool AMDGPUCloseScreen_KMS(ScreenPtr pScreen) /* Clear mask of assigned crtc's in this generation */ pAMDGPUEnt->assigned_crtcs = 0; + drmmode_terminate_leases(pScrn); drmmode_uevent_fini(pScrn, &info->drmmode); amdgpu_drm_queue_close(pScrn); diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 031d826af..fee6fedfb 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -2936,8 +2936,159 @@ fail: return FALSE; } +static void +drmmode_validate_leases(ScrnInfoPtr scrn) +{ +#ifdef XF86_LEASE_VERSION + ScreenPtr screen = scrn->pScreen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + drmModeLesseeListPtr lessees; + RRLeasePtr lease, next; + int l; + + /* We can't talk to the kernel about leases when VT switched */ + if (!scrn->vtSema) + return; + + lessees = drmModeListLessees(pAMDGPUEnt->fd); + if (!lessees) + return; + + xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { + drmmode_lease_private_ptr lease_private = lease->devPrivate; + + for (l = 0; l < lessees->count; l++) { + if (lessees->lessees[l] == lease_private->lessee_id) + break; + } + + /* check to see if the lease has gone away */ + if (l == lessees->count) { + free(lease_private); + lease->devPrivate = NULL; + xf86CrtcLeaseTerminated(lease); + } + } + + free(lessees); +#endif +} + +#ifdef XF86_LEASE_VERSION + +static int +drmmode_create_lease(RRLeasePtr lease, int *fd) +{ + ScreenPtr screen = lease->screen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + drmmode_lease_private_ptr lease_private; + int noutput = lease->numOutputs; + int ncrtc = lease->numCrtcs; + uint32_t *objects; + size_t nobjects; + int lease_fd; + int c, o; + int i; + + nobjects = ncrtc + noutput; + if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || + ncrtc > (SIZE_MAX - noutput)) + return BadValue; + + lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); + if (!lease_private) + return BadAlloc; + + objects = malloc(nobjects * 4); + if (!objects) { + free(lease_private); + return BadAlloc; + } + + i = 0; + + /* Add CRTC ids */ + for (c = 0; c < ncrtc; c++) { + xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + objects[i++] = drmmode_crtc->mode_crtc->crtc_id; + } + + /* Add connector ids */ + for (o = 0; o < noutput; o++) { + xf86OutputPtr output = lease->outputs[o]->devPrivate; + drmmode_output_private_ptr drmmode_output = output->driver_private; + + objects[i++] = drmmode_output->mode_output->connector_id; + } + + /* call kernel to create lease */ + assert (i == nobjects); + + lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, + &lease_private->lessee_id); + + free(objects); + + if (lease_fd < 0) { + free(lease_private); + return BadMatch; + } + + lease->devPrivate = lease_private; + + xf86CrtcLeaseStarted(lease); + + *fd = lease_fd; + return Success; +} + +static void +drmmode_terminate_lease(RRLeasePtr lease) +{ + drmmode_lease_private_ptr lease_private = lease->devPrivate; + ScreenPtr screen = lease->screen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + + if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { + free(lease_private); + lease->devPrivate = NULL; + xf86CrtcLeaseTerminated(lease); + } +} + +#endif // XF86_LEASE_VERSION + +void +drmmode_terminate_leases(ScrnInfoPtr pScrn) +{ +#ifdef XF86_LEASE_VERSION + ScreenPtr screen = xf86ScrnToScreen(pScrn); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + RRLeasePtr lease, next; + + xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { + drmmode_lease_private_ptr lease_private = lease->devPrivate; + drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id); + free(lease_private); + lease->devPrivate = NULL; + RRLeaseTerminated(lease); + RRLeaseFree(lease); + } +#endif +} + static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { - drmmode_xf86crtc_resize + .resize = drmmode_xf86crtc_resize, +#ifdef XF86_LEASE_VERSION + .create_lease = drmmode_create_lease, + .terminate_lease = drmmode_terminate_lease +#endif }; static void @@ -3476,6 +3627,9 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, return FALSE; } + /* Validate leases on VT re-entry */ + drmmode_validate_leases(pScrn); + return TRUE; } @@ -3642,6 +3796,9 @@ restart_destroy: changed = TRUE; } + /* Check to see if a lessee has disappeared */ + drmmode_validate_leases(scrn); + if (changed && dixPrivateKeyRegistered(rrPrivKey)) { #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) RRSetChanged(xf86ScrnToScreen(scrn)); diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 0f0227c71..0646752c2 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -157,6 +157,10 @@ typedef struct { int tear_free; } drmmode_output_private_rec, *drmmode_output_private_ptr; +typedef struct { + uint32_t lessee_id; +} drmmode_lease_private_rec, *drmmode_lease_private_ptr; + enum drmmode_flip_sync { FLIP_VSYNC, @@ -241,6 +245,8 @@ PixmapPtr drmmode_crtc_scanout_create(xf86CrtcPtr crtc, extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode); extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode); +extern void drmmode_terminate_leases(ScrnInfoPtr scrn); + Bool drmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, int x, int y); -- 2.18.0