[PATCH 2/4] modesetting: Take shift in crtc positions for ZaphodHeads configs into account.

Mario Kleiner mario.kleiner.de at gmail.com
Tue Aug 4 15:08:38 PDT 2015


In multi-x-screen ZaphodHeads configurations, there isn't a
one-to-one mapping of kernel provided drmmode crtc index
to the index of the corresponding xf86Crtc inside the
xf86CrtcConfig crtc array anymore, ie. for kernel provided
drmmode->mode_res->crtcs[i], the i'th crtc won't correspond
to the xf86Crtc in the i'th slot of the x-screens xf86CrtcConfig
anymore, once ZaphodHeads has only selected a subset of all crtcs
of a graphics card for a given x-screen, instead of all crtcs.

This breaks the mapping of bit positions in the bit masks returned
in kencoder->possible_crtcs and kencoder->possible_clones. A 1 bit
in position i of those masks allows use of the kernels i'th crtc for
the given kencoder. The X-Servers dix code checks those bit masks
for valid xf86Output -> xf86Crtc assignments, assuming that the i'th
slot xf86CrtcConfigPtr config->crtc[i] corresponds to bit i in the
xf86Output->possibe_crtcs bitmask, and bails if the bitmask doesn't
allow the specified assignment of crtc to output. If ZaphodHeads
breaks the assumption of bit i <-> crtc slot i this ends in failure.

Take this shift of crtc index positions wrt. encoder bitmask bit
positions into account by bit-shifting positions accordingly when
assigning encoder->possible_crtcs to output->possible_crtcs, so
the proper indices match up again for validation by the dix.

This is mostly relevant for nouveau-kms where the possible_crtcs
bitmask is read from VBIOS DCB data. Other kms drivers just
hard-code some generic 'all 1 bits' masks, which don't restrict
encoder to crtc assignments.

Without this patch, ZaphodHeads multi-x-screen breaks, e.g., on the
2010 MacBookPro with nv50, where one crtc is hardwired to the internal
lvds panel, and one crtc is hardwired to the external DP connector,
resulting in a failure where dual-display on single-x-screen works fine,
but assigning each output to a separate x-screen via ZaphodHeads fails
due to the mismatched encoder->possible_crtcs bitmasks.

Tested on radeon-kms dual- and triple-display, intel-kms dual-display,
and nouveau dual-display. Previously failing nv50 cards with hard-wired
outputs now work.

Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>
---
 hw/xfree86/drivers/modesetting/drmmode_display.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 60c35be..4d8892f 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -1387,7 +1387,7 @@ drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
 }
 
 static unsigned int
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
 {
     xf86OutputPtr output;
     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
@@ -1486,7 +1486,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
 
     output->possible_crtcs = 0x7f;
     for (i = 0; i < koutput->count_encoders; i++) {
-        output->possible_crtcs &= kencoders[i]->possible_crtcs;
+        output->possible_crtcs &= kencoders[i]->possible_crtcs >> crtcshift;
     }
     /* work out the possible clones later */
     output->possible_clones = 0;
@@ -1743,6 +1743,7 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
     uint64_t value = 0;
     unsigned int crtcs_needed = 0;
     drmModeResPtr mode_res;
+    int crtcshift;
 
     /* check for dumb capability */
     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
@@ -1760,8 +1761,10 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
     if (!mode_res)
         return FALSE;
 
+    crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
     for (i = 0; i < mode_res->count_connectors; i++)
-        crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE);
+        crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
+                                            crtcshift);
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
                    "Up to %d crtcs needed for screen.\n", crtcs_needed);
@@ -2007,7 +2010,7 @@ drmmode_handle_uevents(int fd, void *closure)
             continue;
 
         changed = TRUE;
-        drmmode_output_init(scrn, drmmode, mode_res, i, 1);
+        drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
     }
 
     if (changed) {
-- 
2.1.4



More information about the xorg-devel mailing list