135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2013 Keith Packard 335c4bbdfSmrg * 435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its 535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that 635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright 735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and 835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or 935c4bbdfSmrg * publicity pertaining to distribution of the software without specific, 1035c4bbdfSmrg * written prior permission. The copyright holders make no representations 1135c4bbdfSmrg * about the suitability of this software for any purpose. It is provided "as 1235c4bbdfSmrg * is" without express or implied warranty. 1335c4bbdfSmrg * 1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2035c4bbdfSmrg * OF THIS SOFTWARE. 2135c4bbdfSmrg */ 2235c4bbdfSmrg 2335c4bbdfSmrg/** @file vblank.c 2435c4bbdfSmrg * 2535c4bbdfSmrg * Support for tracking the DRM's vblank events. 2635c4bbdfSmrg */ 2735c4bbdfSmrg 2835c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H 2935c4bbdfSmrg#include "dix-config.h" 3035c4bbdfSmrg#endif 3135c4bbdfSmrg 3235c4bbdfSmrg#include <unistd.h> 3335c4bbdfSmrg#include <xf86.h> 3435c4bbdfSmrg#include <xf86Crtc.h> 3535c4bbdfSmrg#include "driver.h" 3635c4bbdfSmrg#include "drmmode_display.h" 3735c4bbdfSmrg 3835c4bbdfSmrg/** 3935c4bbdfSmrg * Tracking for outstanding events queued to the kernel. 4035c4bbdfSmrg * 4135c4bbdfSmrg * Each list entry is a struct ms_drm_queue, which has a uint32_t 4235c4bbdfSmrg * value generated from drm_seq that identifies the event and a 4335c4bbdfSmrg * reference back to the crtc/screen associated with the event. It's 4435c4bbdfSmrg * done this way rather than in the screen because we want to be able 4535c4bbdfSmrg * to drain the list of event handlers that should be called at server 4635c4bbdfSmrg * regen time, even though we don't close the drm fd and have no way 4735c4bbdfSmrg * to actually drain the kernel events. 4835c4bbdfSmrg */ 4935c4bbdfSmrgstatic struct xorg_list ms_drm_queue; 5035c4bbdfSmrgstatic uint32_t ms_drm_seq; 5135c4bbdfSmrg 52d44ca368Smrgstatic void box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 5335c4bbdfSmrg{ 5435c4bbdfSmrg dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 5535c4bbdfSmrg dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 5635c4bbdfSmrg if (dest->x1 >= dest->x2) { 5735c4bbdfSmrg dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 5835c4bbdfSmrg return; 5935c4bbdfSmrg } 6035c4bbdfSmrg 6135c4bbdfSmrg dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 6235c4bbdfSmrg dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 6335c4bbdfSmrg if (dest->y1 >= dest->y2) 6435c4bbdfSmrg dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 6535c4bbdfSmrg} 6635c4bbdfSmrg 67d44ca368Smrgstatic void rr_crtc_box(RRCrtcPtr crtc, BoxPtr crtc_box) 684e185dc0Smrg{ 694e185dc0Smrg if (crtc->mode) { 704e185dc0Smrg crtc_box->x1 = crtc->x; 714e185dc0Smrg crtc_box->y1 = crtc->y; 724e185dc0Smrg switch (crtc->rotation) { 734e185dc0Smrg case RR_Rotate_0: 744e185dc0Smrg case RR_Rotate_180: 754e185dc0Smrg default: 764e185dc0Smrg crtc_box->x2 = crtc->x + crtc->mode->mode.width; 774e185dc0Smrg crtc_box->y2 = crtc->y + crtc->mode->mode.height; 784e185dc0Smrg break; 794e185dc0Smrg case RR_Rotate_90: 804e185dc0Smrg case RR_Rotate_270: 814e185dc0Smrg crtc_box->x2 = crtc->x + crtc->mode->mode.height; 824e185dc0Smrg crtc_box->y2 = crtc->y + crtc->mode->mode.width; 834e185dc0Smrg break; 844e185dc0Smrg } 854e185dc0Smrg } else 864e185dc0Smrg crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 874e185dc0Smrg} 884e185dc0Smrg 89d44ca368Smrgstatic int box_area(BoxPtr box) 9035c4bbdfSmrg{ 9135c4bbdfSmrg return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); 9235c4bbdfSmrg} 9335c4bbdfSmrg 94d44ca368Smrgstatic Bool rr_crtc_on(RRCrtcPtr crtc, Bool crtc_is_xf86_hint) 95d44ca368Smrg{ 96d44ca368Smrg if (!crtc) { 97d44ca368Smrg return FALSE; 98d44ca368Smrg } 99d44ca368Smrg if (crtc_is_xf86_hint && crtc->devPrivate) { 100d44ca368Smrg return xf86_crtc_on(crtc->devPrivate); 101d44ca368Smrg } else { 102d44ca368Smrg return !!crtc->mode; 103d44ca368Smrg } 104d44ca368Smrg} 105d44ca368Smrg 10635c4bbdfSmrgBool 107d44ca368Smrgxf86_crtc_on(xf86CrtcPtr crtc) 10835c4bbdfSmrg{ 10935c4bbdfSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 11035c4bbdfSmrg 11135c4bbdfSmrg return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn; 11235c4bbdfSmrg} 11335c4bbdfSmrg 1144e185dc0Smrg 11535c4bbdfSmrg/* 11635c4bbdfSmrg * Return the crtc covering 'box'. If two crtcs cover a portion of 1177e31ba66Smrg * 'box', then prefer the crtc with greater coverage. 11835c4bbdfSmrg */ 1194e185dc0Smrgstatic RRCrtcPtr 120d44ca368Smrgrr_crtc_covering_box(ScreenPtr pScreen, BoxPtr box, Bool screen_is_xf86_hint) 1214e185dc0Smrg{ 122806e81e9Smrg rrScrPrivPtr pScrPriv; 1235a112b11Smrg RROutputPtr primary_output; 1245a112b11Smrg RRCrtcPtr crtc, best_crtc, primary_crtc; 1254e185dc0Smrg int coverage, best_coverage; 1264e185dc0Smrg int c; 1274e185dc0Smrg BoxRec crtc_box, cover_box; 1284e185dc0Smrg 1294e185dc0Smrg best_crtc = NULL; 1304e185dc0Smrg best_coverage = 0; 1314e185dc0Smrg 132806e81e9Smrg if (!dixPrivateKeyRegistered(rrPrivKey)) 133806e81e9Smrg return NULL; 134806e81e9Smrg 135806e81e9Smrg pScrPriv = rrGetScrPriv(pScreen); 136806e81e9Smrg 1374e185dc0Smrg if (!pScrPriv) 1384e185dc0Smrg return NULL; 1394e185dc0Smrg 1405a112b11Smrg primary_crtc = NULL; 1415a112b11Smrg primary_output = RRFirstOutput(pScreen); 1425a112b11Smrg if (primary_output) 1435a112b11Smrg primary_crtc = primary_output->crtc; 1445a112b11Smrg 1454e185dc0Smrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 1464e185dc0Smrg crtc = pScrPriv->crtcs[c]; 1474e185dc0Smrg 1484e185dc0Smrg /* If the CRTC is off, treat it as not covering */ 149d44ca368Smrg if (!rr_crtc_on(crtc, screen_is_xf86_hint)) 1504e185dc0Smrg continue; 1514e185dc0Smrg 152d44ca368Smrg rr_crtc_box(crtc, &crtc_box); 153d44ca368Smrg box_intersect(&cover_box, &crtc_box, box); 154d44ca368Smrg coverage = box_area(&cover_box); 1555a112b11Smrg if ((coverage > best_coverage) || 1565a112b11Smrg (coverage == best_coverage && crtc == primary_crtc)) { 1574e185dc0Smrg best_crtc = crtc; 1584e185dc0Smrg best_coverage = coverage; 1594e185dc0Smrg } 1604e185dc0Smrg } 1614e185dc0Smrg 162d44ca368Smrg return best_crtc; 163d44ca368Smrg} 1644e185dc0Smrg 165d44ca368Smrgstatic RRCrtcPtr 1665a112b11Smrgrr_crtc_covering_box_on_secondary(ScreenPtr pScreen, BoxPtr box) 167d44ca368Smrg{ 168d44ca368Smrg if (!pScreen->isGPU) { 1695a112b11Smrg ScreenPtr secondary; 170d44ca368Smrg RRCrtcPtr crtc = NULL; 1714e185dc0Smrg 1725a112b11Smrg xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 1735a112b11Smrg if (!secondary->is_output_secondary) 1744e185dc0Smrg continue; 1754e185dc0Smrg 1765a112b11Smrg crtc = rr_crtc_covering_box(secondary, box, FALSE); 177d44ca368Smrg if (crtc) 1787e31ba66Smrg return crtc; 1797e31ba66Smrg } 1807e31ba66Smrg } 1817e31ba66Smrg 182d44ca368Smrg return NULL; 18335c4bbdfSmrg} 18435c4bbdfSmrg 18535c4bbdfSmrgxf86CrtcPtr 18635c4bbdfSmrgms_dri2_crtc_covering_drawable(DrawablePtr pDraw) 18735c4bbdfSmrg{ 18835c4bbdfSmrg ScreenPtr pScreen = pDraw->pScreen; 189d44ca368Smrg RRCrtcPtr crtc = NULL; 1907e31ba66Smrg BoxRec box; 19135c4bbdfSmrg 19235c4bbdfSmrg box.x1 = pDraw->x; 19335c4bbdfSmrg box.y1 = pDraw->y; 19435c4bbdfSmrg box.x2 = box.x1 + pDraw->width; 19535c4bbdfSmrg box.y2 = box.y1 + pDraw->height; 19635c4bbdfSmrg 197d44ca368Smrg crtc = rr_crtc_covering_box(pScreen, &box, TRUE); 198d44ca368Smrg if (crtc) { 199d44ca368Smrg return crtc->devPrivate; 200d44ca368Smrg } 201d44ca368Smrg return NULL; 2024e185dc0Smrg} 2034e185dc0Smrg 2044e185dc0SmrgRRCrtcPtr 2054e185dc0Smrgms_randr_crtc_covering_drawable(DrawablePtr pDraw) 2064e185dc0Smrg{ 2074e185dc0Smrg ScreenPtr pScreen = pDraw->pScreen; 208d44ca368Smrg RRCrtcPtr crtc = NULL; 2094e185dc0Smrg BoxRec box; 2104e185dc0Smrg 2114e185dc0Smrg box.x1 = pDraw->x; 2124e185dc0Smrg box.y1 = pDraw->y; 2134e185dc0Smrg box.x2 = box.x1 + pDraw->width; 2144e185dc0Smrg box.y2 = box.y1 + pDraw->height; 2154e185dc0Smrg 216d44ca368Smrg crtc = rr_crtc_covering_box(pScreen, &box, TRUE); 217d44ca368Smrg if (!crtc) { 2185a112b11Smrg crtc = rr_crtc_covering_box_on_secondary(pScreen, &box); 219d44ca368Smrg } 220d44ca368Smrg return crtc; 22135c4bbdfSmrg} 22235c4bbdfSmrg 22335c4bbdfSmrgstatic Bool 22435c4bbdfSmrgms_get_kernel_ust_msc(xf86CrtcPtr crtc, 2257e31ba66Smrg uint64_t *msc, uint64_t *ust) 22635c4bbdfSmrg{ 22735c4bbdfSmrg ScreenPtr screen = crtc->randr_crtc->pScreen; 22835c4bbdfSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 22935c4bbdfSmrg modesettingPtr ms = modesettingPTR(scrn); 23035c4bbdfSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 23135c4bbdfSmrg drmVBlank vbl; 23235c4bbdfSmrg int ret; 23335c4bbdfSmrg 2347e31ba66Smrg if (ms->has_queue_sequence || !ms->tried_queue_sequence) { 2357e31ba66Smrg uint64_t ns; 2367e31ba66Smrg ms->tried_queue_sequence = TRUE; 2377e31ba66Smrg 2387e31ba66Smrg ret = drmCrtcGetSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id, 2397e31ba66Smrg msc, &ns); 2407e31ba66Smrg if (ret != -1 || (errno != ENOTTY && errno != EINVAL)) { 2417e31ba66Smrg ms->has_queue_sequence = TRUE; 2427e31ba66Smrg if (ret == 0) 2437e31ba66Smrg *ust = ns / 1000; 2447e31ba66Smrg return ret == 0; 2457e31ba66Smrg } 2467e31ba66Smrg } 24735c4bbdfSmrg /* Get current count */ 24835c4bbdfSmrg vbl.request.type = DRM_VBLANK_RELATIVE | drmmode_crtc->vblank_pipe; 24935c4bbdfSmrg vbl.request.sequence = 0; 25035c4bbdfSmrg vbl.request.signal = 0; 25135c4bbdfSmrg ret = drmWaitVBlank(ms->fd, &vbl); 25235c4bbdfSmrg if (ret) { 25335c4bbdfSmrg *msc = 0; 25435c4bbdfSmrg *ust = 0; 25535c4bbdfSmrg return FALSE; 25635c4bbdfSmrg } else { 25735c4bbdfSmrg *msc = vbl.reply.sequence; 25835c4bbdfSmrg *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec; 25935c4bbdfSmrg return TRUE; 26035c4bbdfSmrg } 26135c4bbdfSmrg} 26235c4bbdfSmrg 2637e31ba66SmrgBool 2647e31ba66Smrgms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags, 2657e31ba66Smrg uint64_t msc, uint64_t *msc_queued, uint32_t seq) 2667e31ba66Smrg{ 2677e31ba66Smrg ScreenPtr screen = crtc->randr_crtc->pScreen; 2687e31ba66Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2697e31ba66Smrg modesettingPtr ms = modesettingPTR(scrn); 2707e31ba66Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2717e31ba66Smrg drmVBlank vbl; 2727e31ba66Smrg int ret; 2737e31ba66Smrg 2747e31ba66Smrg for (;;) { 2757e31ba66Smrg /* Queue an event at the specified sequence */ 2767e31ba66Smrg if (ms->has_queue_sequence || !ms->tried_queue_sequence) { 2777e31ba66Smrg uint32_t drm_flags = 0; 2787e31ba66Smrg uint64_t kernel_queued; 2797e31ba66Smrg 2807e31ba66Smrg ms->tried_queue_sequence = TRUE; 2817e31ba66Smrg 2827e31ba66Smrg if (flags & MS_QUEUE_RELATIVE) 2837e31ba66Smrg drm_flags |= DRM_CRTC_SEQUENCE_RELATIVE; 2847e31ba66Smrg if (flags & MS_QUEUE_NEXT_ON_MISS) 2857e31ba66Smrg drm_flags |= DRM_CRTC_SEQUENCE_NEXT_ON_MISS; 2867e31ba66Smrg 2877e31ba66Smrg ret = drmCrtcQueueSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id, 2887e31ba66Smrg drm_flags, msc, &kernel_queued, seq); 2897e31ba66Smrg if (ret == 0) { 2907e31ba66Smrg if (msc_queued) 2917e31ba66Smrg *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE); 2927e31ba66Smrg ms->has_queue_sequence = TRUE; 2937e31ba66Smrg return TRUE; 2947e31ba66Smrg } 2957e31ba66Smrg 2967e31ba66Smrg if (ret != -1 || (errno != ENOTTY && errno != EINVAL)) { 2977e31ba66Smrg ms->has_queue_sequence = TRUE; 2987e31ba66Smrg goto check; 2997e31ba66Smrg } 3007e31ba66Smrg } 3017e31ba66Smrg vbl.request.type = DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe; 3027e31ba66Smrg if (flags & MS_QUEUE_RELATIVE) 3037e31ba66Smrg vbl.request.type |= DRM_VBLANK_RELATIVE; 3047e31ba66Smrg else 3057e31ba66Smrg vbl.request.type |= DRM_VBLANK_ABSOLUTE; 3067e31ba66Smrg if (flags & MS_QUEUE_NEXT_ON_MISS) 3077e31ba66Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 3087e31ba66Smrg 3097e31ba66Smrg vbl.request.sequence = msc; 3107e31ba66Smrg vbl.request.signal = seq; 3117e31ba66Smrg ret = drmWaitVBlank(ms->fd, &vbl); 3127e31ba66Smrg if (ret == 0) { 3137e31ba66Smrg if (msc_queued) 3147e31ba66Smrg *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE); 3157e31ba66Smrg return TRUE; 3167e31ba66Smrg } 3177e31ba66Smrg check: 3187e31ba66Smrg if (errno != EBUSY) { 3197e31ba66Smrg ms_drm_abort_seq(scrn, seq); 3207e31ba66Smrg return FALSE; 3217e31ba66Smrg } 3227e31ba66Smrg ms_flush_drm_events(screen); 3237e31ba66Smrg } 3247e31ba66Smrg} 3257e31ba66Smrg 32635c4bbdfSmrg/** 3277e31ba66Smrg * Convert a 32-bit or 64-bit kernel MSC sequence number to a 64-bit local 3287e31ba66Smrg * sequence number, adding in the high 32 bits, and dealing with 32-bit 3297e31ba66Smrg * wrapping if needed. 33035c4bbdfSmrg */ 33135c4bbdfSmrguint64_t 3327e31ba66Smrgms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence, Bool is64bit) 33335c4bbdfSmrg{ 33435c4bbdfSmrg drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; 33535c4bbdfSmrg 3367e31ba66Smrg if (!is64bit) { 3377e31ba66Smrg /* sequence is provided as a 32 bit value from one of the 32 bit apis, 3387e31ba66Smrg * e.g., drmWaitVBlank(), classic vblank events, or pageflip events. 3397e31ba66Smrg * 3407e31ba66Smrg * Track and handle 32-Bit wrapping, somewhat robust against occasional 3417e31ba66Smrg * out-of-order not always monotonically increasing sequence values. 3427e31ba66Smrg */ 3437e31ba66Smrg if ((int64_t) sequence < ((int64_t) drmmode_crtc->msc_prev - 0x40000000)) 3447e31ba66Smrg drmmode_crtc->msc_high += 0x100000000L; 3457e31ba66Smrg 3467e31ba66Smrg if ((int64_t) sequence > ((int64_t) drmmode_crtc->msc_prev + 0x40000000)) 3477e31ba66Smrg drmmode_crtc->msc_high -= 0x100000000L; 3487e31ba66Smrg 3497e31ba66Smrg drmmode_crtc->msc_prev = sequence; 3507e31ba66Smrg 3517e31ba66Smrg return drmmode_crtc->msc_high + sequence; 3527e31ba66Smrg } 3537e31ba66Smrg 3547e31ba66Smrg /* True 64-Bit sequence from Linux 4.15+ 64-Bit drmCrtcGetSequence / 3557e31ba66Smrg * drmCrtcQueueSequence apis and events. Pass through sequence unmodified, 3567e31ba66Smrg * but update the 32-bit tracking variables with reliable ground truth. 3577e31ba66Smrg * 3587e31ba66Smrg * With 64-Bit api in use, the only !is64bit input is from pageflip events, 3595a112b11Smrg * and any pageflip event is usually preceded by some is64bit input from 3607e31ba66Smrg * swap scheduling, so this should provide reliable mapping for pageflip 3617e31ba66Smrg * events based on true 64-bit input as baseline as well. 3627e31ba66Smrg */ 36335c4bbdfSmrg drmmode_crtc->msc_prev = sequence; 3647e31ba66Smrg drmmode_crtc->msc_high = sequence & 0xffffffff00000000; 3657e31ba66Smrg 3667e31ba66Smrg return sequence; 36735c4bbdfSmrg} 36835c4bbdfSmrg 36935c4bbdfSmrgint 3702c83f951Sryoms_get_crtc_ust_msc(xf86CrtcPtr crtc, uint64_t *ust, uint64_t *msc) 37135c4bbdfSmrg{ 3727e31ba66Smrg ScreenPtr screen = crtc->randr_crtc->pScreen; 3737e31ba66Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3747e31ba66Smrg modesettingPtr ms = modesettingPTR(scrn); 3757e31ba66Smrg uint64_t kernel_msc; 37635c4bbdfSmrg 37735c4bbdfSmrg if (!ms_get_kernel_ust_msc(crtc, &kernel_msc, ust)) 37835c4bbdfSmrg return BadMatch; 3797e31ba66Smrg *msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_msc, ms->has_queue_sequence); 38035c4bbdfSmrg 38135c4bbdfSmrg return Success; 38235c4bbdfSmrg} 38335c4bbdfSmrg 38435c4bbdfSmrg/** 38535c4bbdfSmrg * Check for pending DRM events and process them. 38635c4bbdfSmrg */ 38735c4bbdfSmrgstatic void 3887e31ba66Smrgms_drm_socket_handler(int fd, int ready, void *data) 38935c4bbdfSmrg{ 3907e31ba66Smrg ScreenPtr screen = data; 3917e31ba66Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3927e31ba66Smrg modesettingPtr ms = modesettingPTR(scrn); 39335c4bbdfSmrg 3947e31ba66Smrg if (data == NULL) 39535c4bbdfSmrg return; 39635c4bbdfSmrg 3977e31ba66Smrg drmHandleEvent(fd, &ms->event_context); 39835c4bbdfSmrg} 39935c4bbdfSmrg 40035c4bbdfSmrg/* 40135c4bbdfSmrg * Enqueue a potential drm response; when the associated response 40235c4bbdfSmrg * appears, we've got data to pass to the handler from here 40335c4bbdfSmrg */ 40435c4bbdfSmrguint32_t 40535c4bbdfSmrgms_drm_queue_alloc(xf86CrtcPtr crtc, 40635c4bbdfSmrg void *data, 40735c4bbdfSmrg ms_drm_handler_proc handler, 40835c4bbdfSmrg ms_drm_abort_proc abort) 40935c4bbdfSmrg{ 41035c4bbdfSmrg ScreenPtr screen = crtc->randr_crtc->pScreen; 41135c4bbdfSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 41235c4bbdfSmrg struct ms_drm_queue *q; 41335c4bbdfSmrg 41435c4bbdfSmrg q = calloc(1, sizeof(struct ms_drm_queue)); 41535c4bbdfSmrg 41635c4bbdfSmrg if (!q) 41735c4bbdfSmrg return 0; 41835c4bbdfSmrg if (!ms_drm_seq) 41935c4bbdfSmrg ++ms_drm_seq; 42035c4bbdfSmrg q->seq = ms_drm_seq++; 42135c4bbdfSmrg q->scrn = scrn; 42235c4bbdfSmrg q->crtc = crtc; 42335c4bbdfSmrg q->data = data; 42435c4bbdfSmrg q->handler = handler; 42535c4bbdfSmrg q->abort = abort; 42635c4bbdfSmrg 42735c4bbdfSmrg xorg_list_add(&q->list, &ms_drm_queue); 42835c4bbdfSmrg 42935c4bbdfSmrg return q->seq; 43035c4bbdfSmrg} 43135c4bbdfSmrg 43235c4bbdfSmrg/** 43335c4bbdfSmrg * Abort one queued DRM entry, removing it 43435c4bbdfSmrg * from the list, calling the abort function and 43535c4bbdfSmrg * freeing the memory 43635c4bbdfSmrg */ 43735c4bbdfSmrgstatic void 43835c4bbdfSmrgms_drm_abort_one(struct ms_drm_queue *q) 43935c4bbdfSmrg{ 44035c4bbdfSmrg xorg_list_del(&q->list); 44135c4bbdfSmrg q->abort(q->data); 44235c4bbdfSmrg free(q); 44335c4bbdfSmrg} 44435c4bbdfSmrg 44535c4bbdfSmrg/** 44635c4bbdfSmrg * Abort all queued entries on a specific scrn, used 44735c4bbdfSmrg * when resetting the X server 44835c4bbdfSmrg */ 44935c4bbdfSmrgstatic void 45035c4bbdfSmrgms_drm_abort_scrn(ScrnInfoPtr scrn) 45135c4bbdfSmrg{ 45235c4bbdfSmrg struct ms_drm_queue *q, *tmp; 45335c4bbdfSmrg 45435c4bbdfSmrg xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) { 45535c4bbdfSmrg if (q->scrn == scrn) 45635c4bbdfSmrg ms_drm_abort_one(q); 45735c4bbdfSmrg } 45835c4bbdfSmrg} 45935c4bbdfSmrg 46035c4bbdfSmrg/** 46135c4bbdfSmrg * Abort by drm queue sequence number. 46235c4bbdfSmrg */ 46335c4bbdfSmrgvoid 46435c4bbdfSmrgms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq) 46535c4bbdfSmrg{ 46635c4bbdfSmrg struct ms_drm_queue *q, *tmp; 46735c4bbdfSmrg 46835c4bbdfSmrg xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) { 46935c4bbdfSmrg if (q->seq == seq) { 47035c4bbdfSmrg ms_drm_abort_one(q); 47135c4bbdfSmrg break; 47235c4bbdfSmrg } 47335c4bbdfSmrg } 47435c4bbdfSmrg} 47535c4bbdfSmrg 47635c4bbdfSmrg/* 47735c4bbdfSmrg * Externally usable abort function that uses a callback to match a single 47835c4bbdfSmrg * queued entry to abort 47935c4bbdfSmrg */ 48035c4bbdfSmrgvoid 48135c4bbdfSmrgms_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), 48235c4bbdfSmrg void *match_data) 48335c4bbdfSmrg{ 48435c4bbdfSmrg struct ms_drm_queue *q; 48535c4bbdfSmrg 48635c4bbdfSmrg xorg_list_for_each_entry(q, &ms_drm_queue, list) { 48735c4bbdfSmrg if (match(q->data, match_data)) { 48835c4bbdfSmrg ms_drm_abort_one(q); 48935c4bbdfSmrg break; 49035c4bbdfSmrg } 49135c4bbdfSmrg } 49235c4bbdfSmrg} 49335c4bbdfSmrg 49435c4bbdfSmrg/* 49535c4bbdfSmrg * General DRM kernel handler. Looks for the matching sequence number in the 49635c4bbdfSmrg * drm event queue and calls the handler for it. 49735c4bbdfSmrg */ 49835c4bbdfSmrgstatic void 4997e31ba66Smrgms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, Bool is64bit, uint64_t user_data) 50035c4bbdfSmrg{ 50135c4bbdfSmrg struct ms_drm_queue *q, *tmp; 5027e31ba66Smrg uint32_t seq = (uint32_t) user_data; 50335c4bbdfSmrg 50435c4bbdfSmrg xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) { 5057e31ba66Smrg if (q->seq == seq) { 50635c4bbdfSmrg uint64_t msc; 50735c4bbdfSmrg 5087e31ba66Smrg msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame, is64bit); 50935c4bbdfSmrg xorg_list_del(&q->list); 5107e31ba66Smrg q->handler(msc, ns / 1000, q->data); 51135c4bbdfSmrg free(q); 51235c4bbdfSmrg break; 51335c4bbdfSmrg } 51435c4bbdfSmrg } 51535c4bbdfSmrg} 51635c4bbdfSmrg 5177e31ba66Smrgstatic void 5187e31ba66Smrgms_drm_sequence_handler_64bit(int fd, uint64_t frame, uint64_t ns, uint64_t user_data) 5197e31ba66Smrg{ 5207e31ba66Smrg /* frame is true 64 bit wrapped into 64 bit */ 5217e31ba66Smrg ms_drm_sequence_handler(fd, frame, ns, TRUE, user_data); 5227e31ba66Smrg} 5237e31ba66Smrg 5247e31ba66Smrgstatic void 5257e31ba66Smrgms_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, 5267e31ba66Smrg void *user_ptr) 5277e31ba66Smrg{ 5287e31ba66Smrg /* frame is 32 bit wrapped into 64 bit */ 5297e31ba66Smrg ms_drm_sequence_handler(fd, frame, ((uint64_t) sec * 1000000 + usec) * 1000, 5307e31ba66Smrg FALSE, (uint32_t) (uintptr_t) user_ptr); 5317e31ba66Smrg} 5327e31ba66Smrg 53335c4bbdfSmrgBool 53435c4bbdfSmrgms_vblank_screen_init(ScreenPtr screen) 53535c4bbdfSmrg{ 53635c4bbdfSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 53735c4bbdfSmrg modesettingPtr ms = modesettingPTR(scrn); 53835c4bbdfSmrg modesettingEntPtr ms_ent = ms_ent_priv(scrn); 53935c4bbdfSmrg xorg_list_init(&ms_drm_queue); 54035c4bbdfSmrg 5417e31ba66Smrg ms->event_context.version = 4; 54235c4bbdfSmrg ms->event_context.vblank_handler = ms_drm_handler; 54335c4bbdfSmrg ms->event_context.page_flip_handler = ms_drm_handler; 5447e31ba66Smrg ms->event_context.sequence_handler = ms_drm_sequence_handler_64bit; 54535c4bbdfSmrg 54635c4bbdfSmrg /* We need to re-register the DRM fd for the synchronisation 54735c4bbdfSmrg * feedback on every server generation, so perform the 54835c4bbdfSmrg * registration within ScreenInit and not PreInit. 54935c4bbdfSmrg */ 55035c4bbdfSmrg if (ms_ent->fd_wakeup_registered != serverGeneration) { 5517e31ba66Smrg SetNotifyFd(ms->fd, ms_drm_socket_handler, X_NOTIFY_READ, screen); 55235c4bbdfSmrg ms_ent->fd_wakeup_registered = serverGeneration; 55335c4bbdfSmrg ms_ent->fd_wakeup_ref = 1; 55435c4bbdfSmrg } else 55535c4bbdfSmrg ms_ent->fd_wakeup_ref++; 55635c4bbdfSmrg 55735c4bbdfSmrg return TRUE; 55835c4bbdfSmrg} 55935c4bbdfSmrg 56035c4bbdfSmrgvoid 56135c4bbdfSmrgms_vblank_close_screen(ScreenPtr screen) 56235c4bbdfSmrg{ 56335c4bbdfSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 56435c4bbdfSmrg modesettingPtr ms = modesettingPTR(scrn); 56535c4bbdfSmrg modesettingEntPtr ms_ent = ms_ent_priv(scrn); 56635c4bbdfSmrg 56735c4bbdfSmrg ms_drm_abort_scrn(scrn); 56835c4bbdfSmrg 56935c4bbdfSmrg if (ms_ent->fd_wakeup_registered == serverGeneration && 57035c4bbdfSmrg !--ms_ent->fd_wakeup_ref) { 5717e31ba66Smrg RemoveNotifyFd(ms->fd); 57235c4bbdfSmrg } 57335c4bbdfSmrg} 574