Zbigniew Jędrzejewski-Szmek 62fe94
From 0fbd4d113e0d2123e896e8005d1b7fe407c28c05 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Sat, 20 Sep 2014 11:43:32 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal: fix mode sync for connectors
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
The GETXY ioctls of DRM are usually called twice by libdrm: Once to
Zbigniew Jędrzejewski-Szmek 62fe94
retrieve the number of objects, a second time with suitably sized buffers
Zbigniew Jędrzejewski-Szmek 62fe94
to actually retrieve all objects. In grdrm, we avoid these excessive calls
Zbigniew Jędrzejewski-Szmek 62fe94
and instead just call ioctls with cached buffers and resize them if they
Zbigniew Jędrzejewski-Szmek 62fe94
were too small.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
However, connectors need to read the mode list via EDID, which is horribly
Zbigniew Jędrzejewski-Szmek 62fe94
slow. As the kernel still cannot do that asynchronously (seriously, we
Zbigniew Jędrzejewski-Szmek 62fe94
need to fix this!), it has a hack to only do it if count_modes==0. This is
Zbigniew Jędrzejewski-Szmek 62fe94
fine with libdrm, as it calls every ioctl twice, anyway. However, we fail
Zbigniew Jędrzejewski-Szmek 62fe94
horribly with this as we usually never pass 0.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Fix this by calling into GETCONNECTOR ioctls twice in case we received an
Zbigniew Jędrzejewski-Szmek 62fe94
hotplug event. Only in those cases, we need to re-read modes, so this
Zbigniew Jędrzejewski-Szmek 62fe94
should be totally fine.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/grdev-drm.c | 33 ++++++++++++++++++++++++---------
Zbigniew Jędrzejewski-Szmek 62fe94
 1 file changed, 24 insertions(+), 9 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 5cebb0609e..2e55ad326b 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -264,6 +264,7 @@ struct grdrm_card {
Zbigniew Jędrzejewski-Szmek 62fe94
         Hashmap *object_map;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         bool async_hotplug : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        bool hotplug : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
         bool running : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
         bool ready : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
         bool cap_dumb : 1;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -603,12 +604,19 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 res.count_encoders = connector->kern.max_encoders;
Zbigniew Jędrzejewski-Szmek 62fe94
                 res.count_props = connector->kern.max_props;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-                /* Retrieve modes only if we have none. This avoids expensive
Zbigniew Jędrzejewski-Szmek 62fe94
-                 * EDID reads in the kernel, that can slow down resyncs
Zbigniew Jędrzejewski-Szmek 62fe94
-                 * considerably! */
Zbigniew Jędrzejewski-Szmek 62fe94
-                if (connector->kern.n_modes == 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                        res.modes_ptr = PTR_TO_UINT64(connector->kern.modes);
Zbigniew Jędrzejewski-Szmek 62fe94
-                        res.count_modes = connector->kern.max_modes;
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* The kernel reads modes from the EDID information only if we
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * pass count_modes==0. This is a legacy hack for libdrm (which
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * called every ioctl twice). Now we have to adopt.. *sigh*.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * If we never received an hotplug event, there's no reason to
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * sync modes. EDID reads are heavy, so skip that if not
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * required. */
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (card->hotplug) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        if (tries > 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                                res.modes_ptr = PTR_TO_UINT64(connector->kern.modes);
Zbigniew Jędrzejewski-Szmek 62fe94
+                                res.count_modes = connector->kern.max_modes;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                                resized = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        }
Zbigniew Jędrzejewski-Szmek 62fe94
                 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                 r = ioctl(card->fd, DRM_IOCTL_MODE_GETCONNECTOR, &res;;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -689,7 +697,6 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
Zbigniew Jędrzejewski-Szmek 62fe94
                         continue;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.n_encoders = res.count_encoders;
Zbigniew Jędrzejewski-Szmek 62fe94
-                connector->kern.n_modes = res.count_modes;
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.n_props = res.count_props;
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.type = res.connector_type;
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.type_id = res.connector_type_id;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -698,6 +705,8 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.mm_width = res.mm_width;
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.mm_height = res.mm_height;
Zbigniew Jędrzejewski-Szmek 62fe94
                 connector->kern.subpixel = res.subpixel;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (res.modes_ptr == PTR_TO_UINT64(connector->kern.modes))
Zbigniew Jędrzejewski-Szmek 62fe94
+                        connector->kern.n_modes = res.count_modes;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                 break;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2167,6 +2176,7 @@ static void grdrm_card_hotplug(grdrm_card *card) {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         grdrm_card_configure(card);
Zbigniew Jędrzejewski-Szmek 62fe94
         card->ready = true;
Zbigniew Jędrzejewski-Szmek 62fe94
+        card->hotplug = false;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         grdev_session_unpin(card->base.session);
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2374,6 +2384,7 @@ static int grdrm_card_open(grdrm_card *card, int dev_fd) {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        card->hotplug = true;
Zbigniew Jędrzejewski-Szmek 62fe94
         card->fd = fd;
Zbigniew Jędrzejewski-Szmek 62fe94
         fd = -1;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -3029,13 +3040,17 @@ void grdev_drm_card_hotplug(grdev_card *basecard, struct udev_device *ud) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 /* If we get add/remove events on DRM nodes without devnum, we
Zbigniew Jędrzejewski-Szmek 62fe94
                  * got hotplugged DRM objects so refresh the device. */
Zbigniew Jędrzejewski-Szmek 62fe94
                 devnum = udev_device_get_devnum(ud);
Zbigniew Jędrzejewski-Szmek 62fe94
-                if (devnum == 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (devnum == 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        card->hotplug = true;
Zbigniew Jędrzejewski-Szmek 62fe94
                         grdrm_card_hotplug(card);
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
         } else if (streq_ptr(action, "change")) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 /* A change event with HOTPLUG=1 is sent whenever a connector
Zbigniew Jędrzejewski-Szmek 62fe94
                  * changed state. Refresh the device to update our state. */
Zbigniew Jędrzejewski-Szmek 62fe94
                 p = udev_device_get_property_value(ud, "HOTPLUG");
Zbigniew Jędrzejewski-Szmek 62fe94
-                if (streq_ptr(p, "1"))
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (streq_ptr(p, "1")) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        card->hotplug = true;
Zbigniew Jędrzejewski-Szmek 62fe94
                         grdrm_card_hotplug(card);
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 }