xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/vblank.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2013 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 /** @file vblank.c
24  *
25  * Support for tracking the DRM's vblank events.
26  */
27 
28 #ifdef HAVE_DIX_CONFIG_H
29 #include "dix-config.h"
30 #endif
31 
32 #include <unistd.h>
33 #include <xf86.h>
34 #include <xf86Crtc.h>
35 #include "driver.h"
36 #include "drmmode_display.h"
37 
38 /**
39  * Tracking for outstanding events queued to the kernel.
40  *
41  * Each list entry is a struct ms_drm_queue, which has a uint32_t
42  * value generated from drm_seq that identifies the event and a
43  * reference back to the crtc/screen associated with the event.  It's
44  * done this way rather than in the screen because we want to be able
45  * to drain the list of event handlers that should be called at server
46  * regen time, even though we don't close the drm fd and have no way
47  * to actually drain the kernel events.
48  */
49 static struct xorg_list ms_drm_queue;
50 static uint32_t ms_drm_seq;
51 
ms_box_intersect(BoxPtr dest,BoxPtr a,BoxPtr b)52 static void ms_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
53 {
54     dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
55     dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
56     if (dest->x1 >= dest->x2) {
57         dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
58         return;
59     }
60 
61     dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
62     dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
63     if (dest->y1 >= dest->y2)
64         dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
65 }
66 
ms_crtc_box(xf86CrtcPtr crtc,BoxPtr crtc_box)67 static void ms_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
68 {
69     if (crtc->enabled) {
70         crtc_box->x1 = crtc->x;
71         crtc_box->x2 =
72             crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
73         crtc_box->y1 = crtc->y;
74         crtc_box->y2 =
75             crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
76     } else
77         crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
78 }
79 
ms_randr_crtc_box(RRCrtcPtr crtc,BoxPtr crtc_box)80 static void ms_randr_crtc_box(RRCrtcPtr crtc, BoxPtr crtc_box)
81 {
82     if (crtc->mode) {
83         crtc_box->x1 = crtc->x;
84         crtc_box->y1 = crtc->y;
85         switch (crtc->rotation) {
86             case RR_Rotate_0:
87             case RR_Rotate_180:
88             default:
89                 crtc_box->x2 = crtc->x + crtc->mode->mode.width;
90                 crtc_box->y2 = crtc->y + crtc->mode->mode.height;
91                 break;
92             case RR_Rotate_90:
93             case RR_Rotate_270:
94                 crtc_box->x2 = crtc->x + crtc->mode->mode.height;
95                 crtc_box->y2 = crtc->y + crtc->mode->mode.width;
96                 break;
97         }
98     } else
99         crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
100 }
101 
ms_box_area(BoxPtr box)102 static int ms_box_area(BoxPtr box)
103 {
104     return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
105 }
106 
107 Bool
ms_crtc_on(xf86CrtcPtr crtc)108 ms_crtc_on(xf86CrtcPtr crtc)
109 {
110     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
111 
112     return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn;
113 }
114 
115 /*
116  * Return the first output which is connected to an active CRTC on this screen.
117  *
118  * RRFirstOutput() will return an output from a slave screen if it is primary,
119  * which is not the behavior that ms_covering_crtc() wants.
120  */
121 
ms_first_output(ScreenPtr pScreen)122 static RROutputPtr ms_first_output(ScreenPtr pScreen)
123 {
124     rrScrPriv(pScreen);
125     RROutputPtr output;
126     int i, j;
127 
128     if (!pScrPriv)
129         return NULL;
130 
131     if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc &&
132         (pScrPriv->primaryOutput->pScreen == pScreen)) {
133         return pScrPriv->primaryOutput;
134     }
135 
136     for (i = 0; i < pScrPriv->numCrtcs; i++) {
137         RRCrtcPtr crtc = pScrPriv->crtcs[i];
138 
139         for (j = 0; j < pScrPriv->numOutputs; j++) {
140             output = pScrPriv->outputs[j];
141             if (output->crtc == crtc)
142                 return output;
143         }
144     }
145     return NULL;
146 }
147 
148 /*
149  * Return the crtc covering 'box'. If two crtcs cover a portion of
150  * 'box', then prefer the crtc with greater coverage.
151  */
152 
153 static xf86CrtcPtr
ms_covering_xf86_crtc(ScreenPtr pScreen,BoxPtr box,Bool screen_is_ms)154 ms_covering_xf86_crtc(ScreenPtr pScreen, BoxPtr box, Bool screen_is_ms)
155 {
156     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
157     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
158     xf86CrtcPtr crtc, best_crtc;
159     int coverage, best_coverage;
160     int c;
161     BoxRec crtc_box, cover_box;
162     Bool crtc_on;
163 
164     best_crtc = NULL;
165     best_coverage = 0;
166 
167     if (!xf86_config)
168         return NULL;
169 
170     for (c = 0; c < xf86_config->num_crtc; c++) {
171         crtc = xf86_config->crtc[c];
172 
173         if (screen_is_ms)
174             crtc_on = ms_crtc_on(crtc);
175         else
176             crtc_on = crtc->enabled;
177 
178         /* If the CRTC is off, treat it as not covering */
179         if (!crtc_on)
180             continue;
181 
182         ms_crtc_box(crtc, &crtc_box);
183         ms_box_intersect(&cover_box, &crtc_box, box);
184         coverage = ms_box_area(&cover_box);
185         if (coverage > best_coverage) {
186             best_crtc = crtc;
187             best_coverage = coverage;
188         }
189     }
190 
191     /* Fallback to primary crtc for drawable's on slave outputs */
192     if (best_crtc == NULL && !pScreen->isGPU) {
193         RROutputPtr primary_output = NULL;
194         ScreenPtr slave;
195 
196         if (dixPrivateKeyRegistered(rrPrivKey))
197             primary_output = ms_first_output(scrn->pScreen);
198         if (!primary_output || !primary_output->crtc)
199             return NULL;
200 
201         crtc = primary_output->crtc->devPrivate;
202         if (!ms_crtc_on(crtc))
203             return NULL;
204 
205         xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
206             if (!slave->is_output_slave)
207                 continue;
208 
209             if (ms_covering_xf86_crtc(slave, box, FALSE)) {
210                 /* The drawable is on a slave output, return primary crtc */
211                 return crtc;
212             }
213         }
214     }
215 
216     return best_crtc;
217 }
218 
219 static RRCrtcPtr
ms_covering_randr_crtc(ScreenPtr pScreen,BoxPtr box,Bool screen_is_ms)220 ms_covering_randr_crtc(ScreenPtr pScreen, BoxPtr box, Bool screen_is_ms)
221 {
222     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
223     rrScrPrivPtr pScrPriv;
224     RRCrtcPtr crtc, best_crtc;
225     int coverage, best_coverage;
226     int c;
227     BoxRec crtc_box, cover_box;
228     Bool crtc_on;
229 
230     best_crtc = NULL;
231     best_coverage = 0;
232 
233     if (!dixPrivateKeyRegistered(rrPrivKey))
234         return NULL;
235 
236     pScrPriv = rrGetScrPriv(pScreen);
237 
238     if (!pScrPriv)
239         return NULL;
240 
241     for (c = 0; c < pScrPriv->numCrtcs; c++) {
242         crtc = pScrPriv->crtcs[c];
243 
244         if (screen_is_ms) {
245             crtc_on = ms_crtc_on((xf86CrtcPtr) crtc->devPrivate);
246         } else {
247             crtc_on = !!crtc->mode;
248         }
249 
250         /* If the CRTC is off, treat it as not covering */
251         if (!crtc_on)
252             continue;
253 
254         ms_randr_crtc_box(crtc, &crtc_box);
255         ms_box_intersect(&cover_box, &crtc_box, box);
256         coverage = ms_box_area(&cover_box);
257         if (coverage > best_coverage) {
258             best_crtc = crtc;
259             best_coverage = coverage;
260         }
261     }
262 
263     /* Fallback to primary crtc for drawable's on slave outputs */
264     if (best_crtc == NULL && !pScreen->isGPU) {
265         RROutputPtr primary_output = NULL;
266         ScreenPtr slave;
267 
268         if (dixPrivateKeyRegistered(rrPrivKey))
269             primary_output = ms_first_output(scrn->pScreen);
270         if (!primary_output || !primary_output->crtc)
271             return NULL;
272 
273         crtc = primary_output->crtc;
274         if (!ms_crtc_on((xf86CrtcPtr) crtc->devPrivate))
275             return NULL;
276 
277         xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
278             if (!slave->is_output_slave)
279                 continue;
280 
281             if (ms_covering_randr_crtc(slave, box, FALSE)) {
282                 /* The drawable is on a slave output, return primary crtc */
283                 return crtc;
284             }
285         }
286     }
287 
288     return best_crtc;
289 }
290 
291 xf86CrtcPtr
ms_dri2_crtc_covering_drawable(DrawablePtr pDraw)292 ms_dri2_crtc_covering_drawable(DrawablePtr pDraw)
293 {
294     ScreenPtr pScreen = pDraw->pScreen;
295     BoxRec box;
296 
297     box.x1 = pDraw->x;
298     box.y1 = pDraw->y;
299     box.x2 = box.x1 + pDraw->width;
300     box.y2 = box.y1 + pDraw->height;
301 
302     return ms_covering_xf86_crtc(pScreen, &box, TRUE);
303 }
304 
305 RRCrtcPtr
ms_randr_crtc_covering_drawable(DrawablePtr pDraw)306 ms_randr_crtc_covering_drawable(DrawablePtr pDraw)
307 {
308     ScreenPtr pScreen = pDraw->pScreen;
309     BoxRec box;
310 
311     box.x1 = pDraw->x;
312     box.y1 = pDraw->y;
313     box.x2 = box.x1 + pDraw->width;
314     box.y2 = box.y1 + pDraw->height;
315 
316     return ms_covering_randr_crtc(pScreen, &box, TRUE);
317 }
318 
319 static Bool
ms_get_kernel_ust_msc(xf86CrtcPtr crtc,uint64_t * msc,uint64_t * ust)320 ms_get_kernel_ust_msc(xf86CrtcPtr crtc,
321                       uint64_t *msc, uint64_t *ust)
322 {
323     ScreenPtr screen = crtc->randr_crtc->pScreen;
324     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
325     modesettingPtr ms = modesettingPTR(scrn);
326     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
327     drmVBlank vbl;
328     int ret;
329 
330     if (ms->has_queue_sequence || !ms->tried_queue_sequence) {
331         uint64_t ns;
332         ms->tried_queue_sequence = TRUE;
333 
334         ret = drmCrtcGetSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
335                                  msc, &ns);
336         if (ret != -1 || (errno != ENOTTY && errno != EINVAL)) {
337             ms->has_queue_sequence = TRUE;
338             if (ret == 0)
339                 *ust = ns / 1000;
340             return ret == 0;
341         }
342     }
343     /* Get current count */
344     vbl.request.type = DRM_VBLANK_RELATIVE | drmmode_crtc->vblank_pipe;
345     vbl.request.sequence = 0;
346     vbl.request.signal = 0;
347     ret = drmWaitVBlank(ms->fd, &vbl);
348     if (ret) {
349         *msc = 0;
350         *ust = 0;
351         return FALSE;
352     } else {
353         *msc = vbl.reply.sequence;
354         *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec;
355         return TRUE;
356     }
357 }
358 
359 Bool
ms_queue_vblank(xf86CrtcPtr crtc,ms_queue_flag flags,uint64_t msc,uint64_t * msc_queued,uint32_t seq)360 ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
361                 uint64_t msc, uint64_t *msc_queued, uint32_t seq)
362 {
363     ScreenPtr screen = crtc->randr_crtc->pScreen;
364     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
365     modesettingPtr ms = modesettingPTR(scrn);
366     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
367     drmVBlank vbl;
368     int ret;
369 
370     for (;;) {
371         /* Queue an event at the specified sequence */
372         if (ms->has_queue_sequence || !ms->tried_queue_sequence) {
373             uint32_t drm_flags = 0;
374             uint64_t kernel_queued;
375 
376             ms->tried_queue_sequence = TRUE;
377 
378             if (flags & MS_QUEUE_RELATIVE)
379                 drm_flags |= DRM_CRTC_SEQUENCE_RELATIVE;
380             if (flags & MS_QUEUE_NEXT_ON_MISS)
381                 drm_flags |= DRM_CRTC_SEQUENCE_NEXT_ON_MISS;
382 
383             ret = drmCrtcQueueSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
384                                        drm_flags, msc, &kernel_queued, seq);
385             if (ret == 0) {
386                 if (msc_queued)
387                     *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);
388                 ms->has_queue_sequence = TRUE;
389                 return TRUE;
390             }
391 
392             if (ret != -1 || (errno != ENOTTY && errno != EINVAL)) {
393                 ms->has_queue_sequence = TRUE;
394                 goto check;
395             }
396         }
397         vbl.request.type = DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe;
398         if (flags & MS_QUEUE_RELATIVE)
399             vbl.request.type |= DRM_VBLANK_RELATIVE;
400         else
401             vbl.request.type |= DRM_VBLANK_ABSOLUTE;
402         if (flags & MS_QUEUE_NEXT_ON_MISS)
403             vbl.request.type |= DRM_VBLANK_NEXTONMISS;
404 
405         vbl.request.sequence = msc;
406         vbl.request.signal = seq;
407         ret = drmWaitVBlank(ms->fd, &vbl);
408         if (ret == 0) {
409             if (msc_queued)
410                 *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);
411             return TRUE;
412         }
413     check:
414         if (errno != EBUSY) {
415             ms_drm_abort_seq(scrn, seq);
416             return FALSE;
417         }
418         ms_flush_drm_events(screen);
419     }
420 }
421 
422 /**
423  * Convert a 32-bit or 64-bit kernel MSC sequence number to a 64-bit local
424  * sequence number, adding in the high 32 bits, and dealing with 32-bit
425  * wrapping if needed.
426  */
427 uint64_t
ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc,uint64_t sequence,Bool is64bit)428 ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence, Bool is64bit)
429 {
430     drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
431 
432     if (!is64bit) {
433         /* sequence is provided as a 32 bit value from one of the 32 bit apis,
434          * e.g., drmWaitVBlank(), classic vblank events, or pageflip events.
435          *
436          * Track and handle 32-Bit wrapping, somewhat robust against occasional
437          * out-of-order not always monotonically increasing sequence values.
438          */
439         if ((int64_t) sequence < ((int64_t) drmmode_crtc->msc_prev - 0x40000000))
440             drmmode_crtc->msc_high += 0x100000000L;
441 
442         if ((int64_t) sequence > ((int64_t) drmmode_crtc->msc_prev + 0x40000000))
443             drmmode_crtc->msc_high -= 0x100000000L;
444 
445         drmmode_crtc->msc_prev = sequence;
446 
447         return drmmode_crtc->msc_high + sequence;
448     }
449 
450     /* True 64-Bit sequence from Linux 4.15+ 64-Bit drmCrtcGetSequence /
451      * drmCrtcQueueSequence apis and events. Pass through sequence unmodified,
452      * but update the 32-bit tracking variables with reliable ground truth.
453      *
454      * With 64-Bit api in use, the only !is64bit input is from pageflip events,
455      * and any pageflip event is usually preceeded by some is64bit input from
456      * swap scheduling, so this should provide reliable mapping for pageflip
457      * events based on true 64-bit input as baseline as well.
458      */
459     drmmode_crtc->msc_prev = sequence;
460     drmmode_crtc->msc_high = sequence & 0xffffffff00000000;
461 
462     return sequence;
463 }
464 
465 int
ms_get_crtc_ust_msc(xf86CrtcPtr crtc,CARD64 * ust,CARD64 * msc)466 ms_get_crtc_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
467 {
468     ScreenPtr screen = crtc->randr_crtc->pScreen;
469     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
470     modesettingPtr ms = modesettingPTR(scrn);
471     uint64_t kernel_msc;
472 
473     if (!ms_get_kernel_ust_msc(crtc, &kernel_msc, ust))
474         return BadMatch;
475     *msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_msc, ms->has_queue_sequence);
476 
477     return Success;
478 }
479 
480 /**
481  * Check for pending DRM events and process them.
482  */
483 static void
ms_drm_socket_handler(int fd,int ready,void * data)484 ms_drm_socket_handler(int fd, int ready, void *data)
485 {
486     ScreenPtr screen = data;
487     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
488     modesettingPtr ms = modesettingPTR(scrn);
489 
490     if (data == NULL)
491         return;
492 
493     drmHandleEvent(fd, &ms->event_context);
494 }
495 
496 /*
497  * Enqueue a potential drm response; when the associated response
498  * appears, we've got data to pass to the handler from here
499  */
500 uint32_t
ms_drm_queue_alloc(xf86CrtcPtr crtc,void * data,ms_drm_handler_proc handler,ms_drm_abort_proc abort)501 ms_drm_queue_alloc(xf86CrtcPtr crtc,
502                    void *data,
503                    ms_drm_handler_proc handler,
504                    ms_drm_abort_proc abort)
505 {
506     ScreenPtr screen = crtc->randr_crtc->pScreen;
507     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
508     struct ms_drm_queue *q;
509 
510     q = calloc(1, sizeof(struct ms_drm_queue));
511 
512     if (!q)
513         return 0;
514     if (!ms_drm_seq)
515         ++ms_drm_seq;
516     q->seq = ms_drm_seq++;
517     q->scrn = scrn;
518     q->crtc = crtc;
519     q->data = data;
520     q->handler = handler;
521     q->abort = abort;
522 
523     xorg_list_add(&q->list, &ms_drm_queue);
524 
525     return q->seq;
526 }
527 
528 /**
529  * Abort one queued DRM entry, removing it
530  * from the list, calling the abort function and
531  * freeing the memory
532  */
533 static void
ms_drm_abort_one(struct ms_drm_queue * q)534 ms_drm_abort_one(struct ms_drm_queue *q)
535 {
536         xorg_list_del(&q->list);
537         q->abort(q->data);
538         free(q);
539 }
540 
541 /**
542  * Abort all queued entries on a specific scrn, used
543  * when resetting the X server
544  */
545 static void
ms_drm_abort_scrn(ScrnInfoPtr scrn)546 ms_drm_abort_scrn(ScrnInfoPtr scrn)
547 {
548     struct ms_drm_queue *q, *tmp;
549 
550     xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
551         if (q->scrn == scrn)
552             ms_drm_abort_one(q);
553     }
554 }
555 
556 /**
557  * Abort by drm queue sequence number.
558  */
559 void
ms_drm_abort_seq(ScrnInfoPtr scrn,uint32_t seq)560 ms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
561 {
562     struct ms_drm_queue *q, *tmp;
563 
564     xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
565         if (q->seq == seq) {
566             ms_drm_abort_one(q);
567             break;
568         }
569     }
570 }
571 
572 /*
573  * Externally usable abort function that uses a callback to match a single
574  * queued entry to abort
575  */
576 void
ms_drm_abort(ScrnInfoPtr scrn,Bool (* match)(void * data,void * match_data),void * match_data)577 ms_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data),
578              void *match_data)
579 {
580     struct ms_drm_queue *q;
581 
582     xorg_list_for_each_entry(q, &ms_drm_queue, list) {
583         if (match(q->data, match_data)) {
584             ms_drm_abort_one(q);
585             break;
586         }
587     }
588 }
589 
590 /*
591  * General DRM kernel handler. Looks for the matching sequence number in the
592  * drm event queue and calls the handler for it.
593  */
594 static void
ms_drm_sequence_handler(int fd,uint64_t frame,uint64_t ns,Bool is64bit,uint64_t user_data)595 ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, Bool is64bit, uint64_t user_data)
596 {
597     struct ms_drm_queue *q, *tmp;
598     uint32_t seq = (uint32_t) user_data;
599 
600     xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
601         if (q->seq == seq) {
602             uint64_t msc;
603 
604             msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame, is64bit);
605             xorg_list_del(&q->list);
606             q->handler(msc, ns / 1000, q->data);
607             free(q);
608             break;
609         }
610     }
611 }
612 
613 static void
ms_drm_sequence_handler_64bit(int fd,uint64_t frame,uint64_t ns,uint64_t user_data)614 ms_drm_sequence_handler_64bit(int fd, uint64_t frame, uint64_t ns, uint64_t user_data)
615 {
616     /* frame is true 64 bit wrapped into 64 bit */
617     ms_drm_sequence_handler(fd, frame, ns, TRUE, user_data);
618 }
619 
620 static void
ms_drm_handler(int fd,uint32_t frame,uint32_t sec,uint32_t usec,void * user_ptr)621 ms_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec,
622                void *user_ptr)
623 {
624     /* frame is 32 bit wrapped into 64 bit */
625     ms_drm_sequence_handler(fd, frame, ((uint64_t) sec * 1000000 + usec) * 1000,
626                             FALSE, (uint32_t) (uintptr_t) user_ptr);
627 }
628 
629 Bool
ms_vblank_screen_init(ScreenPtr screen)630 ms_vblank_screen_init(ScreenPtr screen)
631 {
632     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
633     modesettingPtr ms = modesettingPTR(scrn);
634     modesettingEntPtr ms_ent = ms_ent_priv(scrn);
635     xorg_list_init(&ms_drm_queue);
636 
637     ms->event_context.version = 4;
638     ms->event_context.vblank_handler = ms_drm_handler;
639     ms->event_context.page_flip_handler = ms_drm_handler;
640     ms->event_context.sequence_handler = ms_drm_sequence_handler_64bit;
641 
642     /* We need to re-register the DRM fd for the synchronisation
643      * feedback on every server generation, so perform the
644      * registration within ScreenInit and not PreInit.
645      */
646     if (ms_ent->fd_wakeup_registered != serverGeneration) {
647         SetNotifyFd(ms->fd, ms_drm_socket_handler, X_NOTIFY_READ, screen);
648         ms_ent->fd_wakeup_registered = serverGeneration;
649         ms_ent->fd_wakeup_ref = 1;
650     } else
651         ms_ent->fd_wakeup_ref++;
652 
653     return TRUE;
654 }
655 
656 void
ms_vblank_close_screen(ScreenPtr screen)657 ms_vblank_close_screen(ScreenPtr screen)
658 {
659     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
660     modesettingPtr ms = modesettingPTR(scrn);
661     modesettingEntPtr ms_ent = ms_ent_priv(scrn);
662 
663     ms_drm_abort_scrn(scrn);
664 
665     if (ms_ent->fd_wakeup_registered == serverGeneration &&
666         !--ms_ent->fd_wakeup_ref) {
667         RemoveNotifyFd(ms->fd);
668     }
669 }
670