xserver: Branch 'master' - 9 commits

Keith Packard keithp at kemper.freedesktop.org
Mon May 11 15:50:20 PDT 2015


 hw/xfree86/common/xf86Config.c                   |   60 ++++
 hw/xfree86/common/xf86Helper.c                   |   13 -
 hw/xfree86/common/xf86str.h                      |   10 
 hw/xfree86/drivers/modesetting/drmmode_display.c |  287 ++++++++++++++++++++---
 hw/xfree86/drivers/modesetting/drmmode_display.h |    2 
 hw/xfree86/man/xorg.conf.man                     |   13 +
 hw/xfree86/modes/xf86Crtc.c                      |  137 ++++++++++
 hw/xfree86/modes/xf86RandR12.c                   |   66 +++++
 hw/xfree86/parser/Configint.h                    |    2 
 hw/xfree86/parser/Screen.c                       |   22 +
 hw/xfree86/parser/xf86Parser.h                   |    5 
 hw/xfree86/parser/xf86tokens.h                   |    1 
 randr/randrstr.h                                 |    9 
 randr/rrmonitor.c                                |    6 
 14 files changed, 577 insertions(+), 56 deletions(-)

New commits:
commit d7091a21d90cf463ae39ec5e8741123218ec5686
Merge: c3ce9d8 8fb8bbb
Author: Keith Packard <keithp at keithp.com>
Date:   Mon May 11 15:49:34 2015 -0700

    Merge remote-tracking branch 'airlied/for-keithp'

diff --cc hw/xfree86/common/xf86Helper.c
index 6a35250,7321a1a..359bac7
--- a/hw/xfree86/common/xf86Helper.c
+++ b/hw/xfree86/common/xf86Helper.c
@@@ -1410,9 -1408,20 +1410,20 @@@ xf86MatchDevice(const char *drivername
              /*
               * we have a matching driver that wasn't claimed, yet
               */
 -            pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr));
 +            pgdp = xnfreallocarray(pgdp, i + 2, sizeof(GDevPtr));
              pgdp[i++] = screensecptr->device;
          }
+         for (k = 0; k < screensecptr->num_gpu_devices; k++) {
+             if ((screensecptr->gpu_devices[k]->driver != NULL)
+             && (xf86NameCmp(screensecptr->gpu_devices[k]->driver, drivername) == 0)
+                 && (!screensecptr->gpu_devices[k]->claimed)) {
+                 /*
+                  * we have a matching driver that wasn't claimed, yet
+                  */
+                 pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr));
+                 pgdp[i++] = screensecptr->gpu_devices[k];
+             }
+         }
      }
  
      /* Then handle the inactive devices */
commit 8fb8bbb3062f1a06621ab7030a9e89d5e8367b35
Author: Dave Airlie <airlied at redhat.com>
Date:   Mon Mar 23 11:33:23 2015 +1000

    modesetting: add tile property support (v2.1)
    
    This adds tiling support to the server modesetting driver,
    it retrieves the tile info from the kernel and translates
    it into the server format and exposes the property.
    
    v2.1: fix resetting tile property (Chris)
    
    Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7f7b560..cae057c 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -749,6 +749,46 @@ drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
     return MODE_OK;
 }
 
+static void
+drmmode_output_attach_tile(xf86OutputPtr output)
+{
+    drmmode_output_private_ptr drmmode_output = output->driver_private;
+    drmModeConnectorPtr koutput = drmmode_output->mode_output;
+    drmmode_ptr drmmode = drmmode_output->drmmode;
+    int i;
+    struct xf86CrtcTileInfo tile_info, *set = NULL;
+
+    if (!koutput) {
+        xf86OutputSetTile(output, NULL);
+        return;
+    }
+
+    /* look for a TILE property */
+    for (i = 0; i < koutput->count_props; i++) {
+        drmModePropertyPtr props;
+        props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+        if (!props)
+            continue;
+
+        if (!(props->flags & DRM_MODE_PROP_BLOB)) {
+            drmModeFreeProperty(props);
+            continue;
+        }
+
+        if (!strcmp(props->name, "TILE")) {
+            drmModeFreePropertyBlob(drmmode_output->tile_blob);
+            drmmode_output->tile_blob =
+                drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+        }
+        drmModeFreeProperty(props);
+    }
+    if (drmmode_output->tile_blob) {
+        if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
+            set = &tile_info;
+    }
+    xf86OutputSetTile(output, set);
+}
+
 static Bool
 has_panel_fitter(xf86OutputPtr output)
 {
@@ -857,6 +897,8 @@ drmmode_output_get_modes(xf86OutputPtr output)
     }
     xf86OutputSetEDID(output, mon);
 
+    drmmode_output_attach_tile(output);
+
     /* modes should already be available */
     for (i = 0; i < koutput->count_modes; i++) {
         Mode = xnfalloc(sizeof(DisplayModeRec));
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index f4989b8..b0e45b6 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -120,6 +120,7 @@ typedef struct {
     drmModeConnectorPtr mode_output;
     drmModeEncoderPtr *mode_encoders;
     drmModePropertyBlobPtr edid_blob;
+    drmModePropertyBlobPtr tile_blob;
     int dpms_enum_id;
     int num_props;
     drmmode_prop_ptr props;
commit 9257b1252da9092ddc676fec9aabe2b33dfad272
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jan 28 17:35:21 2015 +1000

    modesetting: add dynamic connector hotplug support (MST) (v3)
    
    This is ported from the same code in the ati and intel drivers,
    
    It uses the same option name as nvidia and the other DDXes to
    disable tearing down outputs as it is hard to avoid racing with clients.
    
    v2: address two issues with DeleteUnusedDP12 enabled, reported
    by Daniel Martin,
    a) check we have a mode_output before destroying it
    b) only delete *unused* displays (thanks Aaron for clarifying)
    so we check if the output has a crtc and if it does we don't
    delete it.
    
    v3: drop the option to delete unused displays, just encode
    behaviour into the randr spec.
    
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 8dc6b32..7f7b560 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -326,6 +326,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
                 continue;
 
             drmmode_output = output->driver_private;
+            if (drmmode_output->output_id == -1)
+                continue;
             output_ids[output_count] =
                 drmmode_output->mode_output->connector_id;
             output_count++;
@@ -366,10 +368,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
         /* go through all the outputs and force DPMS them back on? */
         for (i = 0; i < xf86_config->num_output; i++) {
             xf86OutputPtr output = xf86_config->output[i];
+            drmmode_output_private_ptr drmmode_output;
 
             if (output->crtc != crtc)
                 continue;
 
+            drmmode_output = output->driver_private;
+            if (drmmode_output->output_id == -1)
+                continue;
             output->funcs->dpms(output, DPMSModeOn);
         }
     }
@@ -712,6 +718,9 @@ drmmode_output_detect(xf86OutputPtr output)
     drmmode_ptr drmmode = drmmode_output->drmmode;
     xf86OutputStatus status;
 
+    if (drmmode_output->output_id == -1)
+        return XF86OutputStatusDisconnected;
+
     drmModeFreeConnector(drmmode_output->mode_output);
 
     drmmode_output->mode_output =
@@ -873,11 +882,13 @@ drmmode_output_destroy(xf86OutputPtr output)
         free(drmmode_output->props[i].atoms);
     }
     free(drmmode_output->props);
-    for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
-        drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+    if (drmmode_output->mode_output) {
+        for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
+            drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+        }
+        drmModeFreeConnector(drmmode_output->mode_output);
     }
     free(drmmode_output->mode_encoders);
-    drmModeFreeConnector(drmmode_output->mode_output);
     free(drmmode_output);
     output->driver_private = NULL;
 }
@@ -1111,22 +1122,134 @@ static const char *const output_names[] = {
     "DSI",
 };
 
+static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int i;
+    for (i = 0; i < xf86_config->num_output; i++) {
+        xf86OutputPtr output = xf86_config->output[i];
+        drmmode_output_private_ptr drmmode_output;
+
+        drmmode_output = output->driver_private;
+        if (drmmode_output->output_id == id)
+            return output;
+    }
+    return NULL;
+}
+
+static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
+{
+    char *conn;
+    char conn_id[5];
+    int id, len;
+    char *blob_data;
+
+    if (!path_blob)
+        return -1;
+
+    blob_data = path_blob->data;
+    /* we only handle MST paths for now */
+    if (strncmp(blob_data, "mst:", 4))
+        return -1;
+
+    conn = strchr(blob_data + 4, '-');
+    if (!conn)
+        return -1;
+    len = conn - (blob_data + 4);
+    if (len + 1> 5)
+        return -1;
+    memcpy(conn_id, blob_data + 4, len);
+    conn_id[len + 1] = '\0';
+    id = strtoul(conn_id, NULL, 10);
+
+    *conn_base_id = id;
+
+    *path = conn + 1;
+    return 0;
+}
+
+static void
+drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
+		    drmModePropertyBlobPtr path_blob)
+{
+    int ret;
+    char *extra_path;
+    int conn_id;
+    xf86OutputPtr output;
+
+    ret = parse_path_blob(path_blob, &conn_id, &extra_path);
+    if (ret == -1)
+        goto fallback;
+
+    output = find_output(pScrn, conn_id);
+    if (!output)
+        goto fallback;
+
+    snprintf(name, 32, "%s-%s", output->name, extra_path);
+    return;
+
+ fallback:
+    if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
+        snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1);
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+    else if (pScrn->is_gpu)
+        snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
+#endif
+    else
+        snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
+}
+
 static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic)
 {
     xf86OutputPtr output;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     drmModeConnectorPtr koutput;
     drmModeEncoderPtr *kencoders = NULL;
     drmmode_output_private_ptr drmmode_output;
     drmModePropertyPtr props;
     char name[32];
     int i;
+    drmModePropertyBlobPtr path_blob = NULL;
 
     koutput =
         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
     if (!koutput)
         return;
 
+    for (i = 0; i < koutput->count_props; i++) {
+        props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+        if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+            if (!strcmp(props->name, "PATH")) {
+                path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+                drmModeFreeProperty(props);
+                break;
+            }
+            drmModeFreeProperty(props);
+        }
+    }
+
+    drmmode_create_name(pScrn, koutput, name, path_blob);
+
+    if (path_blob)
+        drmModeFreePropertyBlob(path_blob);
+
+    if (path_blob && dynamic) {
+        /* see if we have an output with this name already
+           and hook stuff up */
+        for (i = 0; i < xf86_config->num_output; i++) {
+            output = xf86_config->output[i];
+
+            if (strncmp(output->name, name, 32))
+                continue;
+
+            drmmode_output = output->driver_private;
+            drmmode_output->output_id = mode_res->connectors[num];
+            drmmode_output->mode_output = koutput;
+            return;
+        }
+    }
+
     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
     if (!kencoders) {
         goto out_free_encoders;
@@ -1139,17 +1262,6 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
         }
     }
 
-    /* need to do smart conversion here for compat with non-kms ATI driver */
-    if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
-        snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1);
-    else if (pScrn->is_gpu)
-        snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type],
-                 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
-                 koutput->connector_type_id - 1);
-    else
-        snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
-                 koutput->connector_type_id - 1);
-
     output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
     if (!output) {
         goto out_free_encoders;
@@ -1192,6 +1304,8 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
         }
     }
 
+    if (dynamic)
+        output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
     return;
  out_free_encoders:
     if (kencoders) {
@@ -1451,7 +1565,7 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
             drmmode_crtc_init(pScrn, drmmode, mode_res, i);
 
     for (i = 0; i < mode_res->count_connectors; i++)
-        drmmode_output_init(pScrn, drmmode, mode_res, i);
+        drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE);
 
     /* workout clones */
     drmmode_clones_init(pScrn, drmmode, mode_res);
@@ -1620,11 +1734,78 @@ drmmode_handle_uevents(int fd, void *closure)
     drmmode_ptr drmmode = closure;
     ScrnInfoPtr scrn = drmmode->scrn;
     struct udev_device *dev;
+    drmModeResPtr mode_res;
+    xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
+    int i, j;
+    Bool found;
+    Bool changed = FALSE;
 
     dev = udev_monitor_receive_device(drmmode->uevent_monitor);
     if (!dev)
         return;
 
+    mode_res = drmModeGetResources(drmmode->fd);
+    if (!mode_res)
+        goto out;
+
+    if (mode_res->count_crtcs != config->num_crtc) {
+        ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc);
+        goto out_free_res;
+    }
+
+    /* figure out if we have gotten rid of any connectors
+       traverse old output list looking for outputs */
+    for (i = 0; i < config->num_output; i++) {
+        xf86OutputPtr output = config->output[i];
+        drmmode_output_private_ptr drmmode_output;
+
+        drmmode_output = output->driver_private;
+        found = FALSE;
+        for (j = 0; j < mode_res->count_connectors; j++) {
+            if (mode_res->connectors[j] == drmmode_output->output_id) {
+                found = TRUE;
+                break;
+            }
+        }
+        if (found)
+            continue;
+
+        drmModeFreeConnector(drmmode_output->mode_output);
+        drmmode_output->mode_output = NULL;
+        drmmode_output->output_id = -1;
+
+        changed = TRUE;
+    }
+
+    /* find new output ids we don't have outputs for */
+    for (i = 0; i < mode_res->count_connectors; i++) {
+        found = FALSE;
+
+        for (j = 0; j < config->num_output; j++) {
+            xf86OutputPtr output = config->output[j];
+            drmmode_output_private_ptr drmmode_output;
+
+            drmmode_output = output->driver_private;
+            if (mode_res->connectors[i] == drmmode_output->output_id) {
+                found = TRUE;
+                break;
+            }
+        }
+        if (found)
+            continue;
+
+        changed = TRUE;
+        drmmode_output_init(scrn, drmmode, mode_res, i, 1);
+    }
+
+    if (changed) {
+        RRSetChanged(xf86ScrnToScreen(scrn));
+        RRTellChanged(xf86ScrnToScreen(scrn));
+    }
+
+out_free_res:
+    drmModeFreeResources(mode_res);
+out:
     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
     udev_device_unref(dev);
 }
commit 33422d160bff3117b413a62d82b168e84f1aa8f6
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jan 28 17:25:00 2015 +1000

    modesetting: stop caching mode resources
    
    There is no need to cache the mode resources and with dynamic
    connectors for mst support we don't want to. So first clean that
    up before adding dynamic connector support.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 1ea799b..8dc6b32 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -687,7 +687,7 @@ drmmode_crtc_vblank_pipe(int crtc_id)
 }
 
 static void
-drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
 {
     xf86CrtcPtr crtc;
     drmmode_crtc_private_ptr drmmode_crtc;
@@ -698,7 +698,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
 
     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
     drmmode_crtc->mode_crtc =
-        drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
+        drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
     drmmode_crtc->drmmode = drmmode;
     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
     crtc->driver_private = drmmode_crtc;
@@ -1112,7 +1112,7 @@ static const char *const output_names[] = {
 };
 
 static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
 {
     xf86OutputPtr output;
     drmModeConnectorPtr koutput;
@@ -1123,7 +1123,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
     int i;
 
     koutput =
-        drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
+        drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
     if (!koutput)
         return;
 
@@ -1161,7 +1161,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
         goto out_free_encoders;
     }
 
-    drmmode_output->output_id = drmmode->mode_res->connectors[num];
+    drmmode_output->output_id = mode_res->connectors[num];
     drmmode_output->mode_output = koutput;
     drmmode_output->mode_encoders = kencoders;
     drmmode_output->drmmode = drmmode;
@@ -1231,7 +1231,7 @@ find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
 }
 
 static void
-drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
+drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
 {
     int i, j;
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1246,8 +1246,8 @@ drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
             int k;
 
-            for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
-                if (drmmode->mode_res->encoders[k] ==
+            for (k = 0; k < mode_res->count_encoders; k++) {
+                if (mode_res->encoders[k] ==
                     drmmode_output->mode_encoders[j]->encoder_id)
                     drmmode_output->enc_mask |= (1 << k);
             }
@@ -1425,6 +1425,7 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
     int i;
     int ret;
     uint64_t value = 0;
+    drmModeResPtr mode_res;
 
     /* check for dumb capability */
     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
@@ -1438,23 +1439,24 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
 
     drmmode->scrn = pScrn;
     drmmode->cpp = cpp;
-    drmmode->mode_res = drmModeGetResources(drmmode->fd);
-    if (!drmmode->mode_res)
+    mode_res = drmModeGetResources(drmmode->fd);
+    if (!mode_res)
         return FALSE;
 
-    xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
-                         drmmode->mode_res->max_height);
-    for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
+    xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
+                         mode_res->max_height);
+    for (i = 0; i < mode_res->count_crtcs; i++)
         if (!xf86IsEntityShared(pScrn->entityList[0]) ||
             pScrn->confScreen->device->screen == i)
-            drmmode_crtc_init(pScrn, drmmode, i);
+            drmmode_crtc_init(pScrn, drmmode, mode_res, i);
 
-    for (i = 0; i < drmmode->mode_res->count_connectors; i++)
-        drmmode_output_init(pScrn, drmmode, i);
+    for (i = 0; i < mode_res->count_connectors; i++)
+        drmmode_output_init(pScrn, drmmode, mode_res, i);
 
     /* workout clones */
-    drmmode_clones_init(pScrn, drmmode);
+    drmmode_clones_init(pScrn, drmmode, mode_res);
 
+    drmModeFreeResources(mode_res);
 #if XF86_CRTC_VERSION >= 5
     xf86ProviderSetup(pScrn, NULL, "modesetting");
 #endif
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 3a8959a..f4989b8 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -47,7 +47,6 @@ typedef struct {
     int fd;
     unsigned fb_id;
     unsigned old_fb_id;
-    drmModeResPtr mode_res;
     drmModeFBPtr mode_fb;
     int cpp;
     ScrnInfoPtr scrn;
commit a9ac02f6949357619684dd98ff6cf05489e62e55
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Apr 1 12:13:51 2015 +1000

    xf86Crtc/monitors: create initial monitors for tiled outputs
    
    This creates an automatic monitor for a tiled monitor at startup.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index b1c306a..642127e 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1564,6 +1564,70 @@ xf86RandR12CreateObjects12(ScreenPtr pScreen)
     return TRUE;
 }
 
+static void
+xf86RandR12CreateMonitors(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int o, ot;
+    int ht, vt;
+    int ret;
+    char buf[25];
+
+    for (o = 0; o < config->num_output; o++) {
+        xf86OutputPtr output = config->output[o];
+        struct xf86CrtcTileInfo *tile_info = &output->tile_info, *this_tile;
+        RRMonitorPtr monitor;
+        int output_num, num_outputs;
+        if (!tile_info->group_id)
+            continue;
+
+        if (tile_info->tile_h_loc ||
+            tile_info->tile_v_loc)
+            continue;
+
+        num_outputs = tile_info->num_h_tile * tile_info->num_v_tile;
+
+        monitor = RRMonitorAlloc(num_outputs);
+        if (!monitor)
+            return;
+        monitor->pScreen = pScreen;
+        snprintf(buf, 25, "Auto-Monitor-%d", tile_info->group_id);
+        monitor->name = MakeAtom(buf, strlen(buf), TRUE);
+        monitor->primary = 0;
+        monitor->automatic = TRUE;
+        memset(&monitor->geometry.box, 0, sizeof(monitor->geometry.box));
+
+        output_num = 0;
+        for (ht = 0; ht < tile_info->num_h_tile; ht++) {
+            for (vt = 0; vt < tile_info->num_v_tile; vt++) {
+
+                for (ot = 0; ot < config->num_output; ot++) {
+                    this_tile = &config->output[ot]->tile_info;
+
+                    if (this_tile->group_id != tile_info->group_id)
+                        continue;
+
+                    if (this_tile->tile_h_loc != ht ||
+                        this_tile->tile_v_loc != vt)
+                        continue;
+
+                    monitor->outputs[output_num] = config->output[ot]->randr_output->id;
+                    output_num++;
+
+                }
+
+            }
+        }
+
+        ret = RRMonitorAdd(serverClient, pScreen, monitor);
+        if (ret) {
+            RRMonitorFree(monitor);
+            return;
+        }
+    }
+}
+
 static Bool
 xf86RandR12CreateScreenResources12(ScreenPtr pScreen)
 {
@@ -1579,6 +1643,8 @@ xf86RandR12CreateScreenResources12(ScreenPtr pScreen)
 
     RRScreenSetSizeRange(pScreen, config->minWidth, config->minHeight,
                          config->maxWidth, config->maxHeight);
+
+    xf86RandR12CreateMonitors(pScreen);
     return TRUE;
 }
 
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 438a52a..03974fd 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -1016,6 +1016,15 @@ RRMonitorFreeList(RRMonitorPtr monitors, int nmon);
 void
 RRMonitorClose(ScreenPtr screen);
 
+RRMonitorPtr
+RRMonitorAlloc(int noutput);
+
+int
+RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor);
+
+void
+RRMonitorFree(RRMonitorPtr monitor);
+
 int
 ProcRRGetMonitors(ClientPtr client);
 
diff --git a/randr/rrmonitor.c b/randr/rrmonitor.c
index fbdd352..7e96263 100644
--- a/randr/rrmonitor.c
+++ b/randr/rrmonitor.c
@@ -389,13 +389,13 @@ RRMonitorCountList(ScreenPtr screen)
     return nmon;
 }
 
-static void
+void
 RRMonitorFree(RRMonitorPtr monitor)
 {
     free(monitor);
 }
 
-static RRMonitorPtr
+RRMonitorPtr
 RRMonitorAlloc(int noutput)
 {
     RRMonitorPtr        monitor;
@@ -451,7 +451,7 @@ RRMonitorMatchesOutputName(ScreenPtr screen, Atom name)
     return FALSE;
 }
 
-static int
+int
 RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor)
 {
     rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
commit afd18bce6a81106a12fd750d5fa09d05c09d37a8
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Apr 1 14:32:00 2015 +1000

    xf86Crtc: setup tiled monitors correctly in right of
    
    This puts the tiles of the monitor in the right place at
    X server startup.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 8a4ef5e..585bd98 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -2128,6 +2128,8 @@ xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
 {
     int o;
     int w = 0;
+    Bool has_tile = FALSE;
+    uint32_t configured_outputs;
 
     if (scrn->preferClone)
         return FALSE;
@@ -2149,16 +2151,75 @@ xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
         return FALSE;
 
     w = 0;
+    configured_outputs = 0;
+
     for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
         DisplayModePtr mode =
             xf86OutputHasPreferredMode(config->output[o], width, height);
 
+        if (configured_outputs & (1 << o))
+            continue;
+
+        if (config->output[o]->tile_info.group_id) {
+            has_tile = TRUE;
+            continue;
+        }
+
         config->output[o]->initial_x = w;
         w += mode->HDisplay;
 
+        configured_outputs |= (1 << o);
         modes[o] = mode;
     }
 
+    if (has_tile) {
+        for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
+            int ht, vt, ot;
+            int add_x, cur_x = w;
+            struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile;
+            if (configured_outputs & (1 << o))
+                continue;
+            if (!tile_info->group_id)
+                continue;
+
+            if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0)
+                continue;
+
+            for (ht = 0; ht < tile_info->num_h_tile; ht++) {
+                int cur_y = 0;
+                add_x = 0;
+                for (vt = 0; vt < tile_info->num_v_tile; vt++) {
+
+                    for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) {
+
+                        DisplayModePtr mode =
+                            xf86OutputHasPreferredMode(config->output[ot], width, height);
+                        if (!config->output[ot]->tile_info.group_id)
+                            continue;
+
+                        this_tile = &config->output[ot]->tile_info;
+                        if (this_tile->group_id != tile_info->group_id)
+                            continue;
+
+                        if (this_tile->tile_h_loc != ht ||
+                            this_tile->tile_v_loc != vt)
+                            continue;
+
+                        config->output[ot]->initial_x = cur_x;
+                        config->output[ot]->initial_y = cur_y;
+
+                        if (vt == 0)
+                            add_x = this_tile->tile_h_size;
+                        cur_y += this_tile->tile_v_size;
+                        configured_outputs |= (1 << ot);
+                        modes[ot] = mode;
+                    }
+                }
+                cur_x += add_x;
+            }
+            w = cur_x;
+        }
+    }
     return TRUE;
 }
 
commit e472dd89420f671685c11b06d376ff146d54c3b8
Author: Adam Jackson <ajax at redhat.com>
Date:   Tue Jul 28 11:07:13 2009 -0400

    xf86Crtc: right-of placement by default.
    
    Change the X server default to do right-of placement
    at startup. This gives an option to allow drivers to
    override this placement, which has been used for server
    drivers where both heads are not in the same physical
    place.
    
    Been in Fedora for a few years, but for tiled monitors
    we really want something along these lines.
    
    This is an ABI break.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h
index 62c0ce9..a58fafe 100644
--- a/hw/xfree86/common/xf86str.h
+++ b/hw/xfree86/common/xf86str.h
@@ -516,6 +516,9 @@ typedef struct _confdrirec {
 #define NUM_RESERVED_POINTERS		14
 #define NUM_RESERVED_FUNCS		10
 
+/* let clients know they can use this */
+#define XF86_SCRN_HAS_PREFER_CLONE 1
+
 typedef void *(*funcPointer) (void);
 
 /* flags for depth 24 pixmap options */
@@ -772,6 +775,9 @@ typedef struct _ScrnInfoRec {
     ClockRangePtr clockRanges;
     int adjustFlags;
 
+    /* initial rightof support disable */
+    int                 preferClone;
+
     /*
      * These can be used when the minor ABI version is incremented.
      * The NUM_* parameters must be reduced appropriately to keep the
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index a194724..8a4ef5e 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -1123,6 +1123,15 @@ xf86InitialOutputPositions(ScrnInfoPtr scrn, DisplayModePtr * modes)
     int o;
     int min_x, min_y;
 
+    /* check for initial right-of heuristic */
+    for (o = 0; o < config->num_output; o++)
+    {
+        xf86OutputPtr output = config->output[o];
+
+        if (output->initial_x || output->initial_y)
+            return TRUE;
+    }
+
     for (o = 0; o < config->num_output; o++) {
         xf86OutputPtr output = config->output[o];
 
@@ -2102,6 +2111,57 @@ bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
     return match;
 }
 
+static int
+numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled)
+{
+    int i = 0, p;
+
+    for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
+
+    return i;
+}
+
+static Bool
+xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
+                  DisplayModePtr *modes, Bool *enabled,
+                  int width, int height)
+{
+    int o;
+    int w = 0;
+
+    if (scrn->preferClone)
+        return FALSE;
+
+    if (numEnabledOutputs(config, enabled) < 2)
+        return FALSE;
+
+    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
+        DisplayModePtr mode =
+            xf86OutputHasPreferredMode(config->output[o], width, height);
+
+        if (!mode)
+            return FALSE;
+
+        w += mode->HDisplay;
+    }
+
+    if (w > width)
+        return FALSE;
+
+    w = 0;
+    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
+        DisplayModePtr mode =
+            xf86OutputHasPreferredMode(config->output[o], width, height);
+
+        config->output[o]->initial_x = w;
+        w += mode->HDisplay;
+
+        modes[o] = mode;
+    }
+
+    return TRUE;
+}
+
 static Bool
 xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
                     DisplayModePtr * modes, Bool *enabled,
@@ -2178,14 +2238,10 @@ xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
      */
     if (!ret)
         do {
-            int i = 0;
             float aspect = 0.0;
             DisplayModePtr a = NULL, b = NULL;
 
-            /* count the number of enabled outputs */
-            for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++);
-
-            if (i != 1)
+            if (numEnabledOutputs(config, enabled) != 1)
                 break;
 
             p = -1;
@@ -2491,6 +2547,8 @@ xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow)
     else {
         if (xf86TargetUserpref(scrn, config, modes, enabled, width, height))
             xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n");
+        else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height))
+            xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n");
         else if (xf86TargetPreferred
                  (scrn, config, modes, enabled, width, height))
             xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n");
@@ -2510,9 +2568,11 @@ xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow)
                        "Output %s enabled but has no modes\n",
                        config->output[o]->name);
         else
-            xf86DrvMsg(scrn->scrnIndex, X_INFO,
-                       "Output %s using initial mode %s\n",
-                       config->output[o]->name, modes[o]->name);
+            xf86DrvMsg (scrn->scrnIndex, X_INFO,
+                        "Output %s using initial mode %s +%d+%d\n",
+                        config->output[o]->name, modes[o]->name,
+                        config->output[o]->initial_x,
+                        config->output[o]->initial_y);
     }
 
     /*
commit 69e4b8e602ecc7b69c75988a447ec5b509b22402
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Mar 31 16:56:42 2015 +1000

    xfree86: attempt to autoconfig gpu slave devices (v3)
    
    This allows us to skip the screen section, the first
    Device section will get assigned to the screen,
    any remaining ones will get assigned to the GPUDevice
    sections for the screen.
    
    v2: fix the skipping unsuitable screen logic (Aaron)
    v3: fix segfault if not conf file (me, 5s after sending v2)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index 88225a2..7d4ec3d 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -1825,13 +1825,34 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum,
         screenp->device = NULL;
     }
 
-    for (i = 0; i < conf_screen->num_gpu_devices; i++) {
-        screenp->gpu_devices[i] = xnfcalloc(1, sizeof(GDevRec));
-        if (configDevice(screenp->gpu_devices[i], conf_screen->scrn_gpu_devices[i], TRUE, TRUE)) {
-            screenp->gpu_devices[i]->myScreenSection = screenp;
+    if (conf_screen->num_gpu_devices == 0 && xf86configptr->conf_device_lst) {
+        XF86ConfDevicePtr sdevice = xf86configptr->conf_device_lst->list.next;
+
+        for (i = 0; i < MAX_GPUDEVICES; i++) {
+            if (!sdevice)
+                break;
+
+            FIND_SUITABLE (XF86ConfDevicePtr, sdevice, conf_screen->scrn_gpu_devices[i]);
+            if (!conf_screen->scrn_gpu_devices[i])
+                break;
+            screenp->gpu_devices[i] = xnfcalloc(1, sizeof(GDevRec));
+            if (configDevice(screenp->gpu_devices[i], conf_screen->scrn_gpu_devices[i], TRUE, TRUE)) {
+                screenp->gpu_devices[i]->myScreenSection = screenp;
+            }
+            sdevice = conf_screen->scrn_gpu_devices[i]->list.next;
         }
+        screenp->num_gpu_devices = i;
+
+    } else {
+        for (i = 0; i < conf_screen->num_gpu_devices; i++) {
+            screenp->gpu_devices[i] = xnfcalloc(1, sizeof(GDevRec));
+            if (configDevice(screenp->gpu_devices[i], conf_screen->scrn_gpu_devices[i], TRUE, TRUE)) {
+                screenp->gpu_devices[i]->myScreenSection = screenp;
+            }
+        }
+        screenp->num_gpu_devices = conf_screen->num_gpu_devices;
     }
-    screenp->num_gpu_devices = conf_screen->num_gpu_devices;
+
     screenp->options = conf_screen->scrn_option_lst;
 
     /*
commit 3b6930c5d02d8fc0d22fe7955e1ef2af61727705
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Mar 31 16:42:36 2015 +1000

    xserver: add xorg.conf support for gpu devices. (v2.1)
    
    This allows gpu devices to be specified in xorg.conf Screen sections.
    
    Section "Device"
            Driver "intel"
            Identifier "intel0"
            Option "AccelMethod" "uxa"
    EndSection
    
    Section "Device"
            Driver "modesetting"
            Identifier "usb0"
    EndSection
    
    Section "Screen"
            Identifier "screen"
            Device "intel0"
            GPUDevice "usb0"
    EndSection
    
    This should allow for easier tweaking of driver options which
    currently mess up the GPU device discovery process.
    
    v2: add error handling for more than 4 devices, (Emil)
    fixup CONF_ defines to consistency
    add MAX_GPUDEVICES define
    (yes there is two defines, this is consistent
    with everywhere else).
    remove braces around slp (Mark Kettenis)
    man page fixups (Aaron)
    v2.1: fixup whitespace (Aaron)
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index d42572f..88225a2 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -126,7 +126,7 @@ static Bool configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen,
                          int scrnum, MessageType from);
 static Bool configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor);
 static Bool configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device,
-                         Bool active);
+                         Bool active, Bool gpu);
 static Bool configInput(InputInfoPtr pInfo, XF86ConfInputPtr conf_input,
                         MessageType from);
 static Bool configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display);
@@ -390,7 +390,7 @@ const char **
 xf86DriverlistFromConfig(void)
 {
     int count = 0;
-    int j;
+    int j, k;
     const char **modulearray;
     screenLayoutPtr slp;
 
@@ -411,8 +411,10 @@ xf86DriverlistFromConfig(void)
      */
     if (xf86ConfigLayout.screens) {
         slp = xf86ConfigLayout.screens;
-        while ((slp++)->screen) {
+        while (slp->screen) {
             count++;
+            count += slp->screen->num_gpu_devices;
+            slp++;
         }
     }
 
@@ -435,6 +437,10 @@ xf86DriverlistFromConfig(void)
     while (slp->screen) {
         modulearray[count] = slp->screen->device->driver;
         count++;
+        for (k = 0; k < slp->screen->num_gpu_devices; k++) {
+            modulearray[count] = slp->screen->gpu_devices[k]->driver;
+            count++;
+        }
         slp++;
     }
 
@@ -1631,7 +1637,7 @@ configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout,
     idp = conf_layout->lay_inactive_lst;
     count = 0;
     while (idp) {
-        if (!configDevice(&gdp[count], idp->inactive_device, FALSE))
+        if (!configDevice(&gdp[count], idp->inactive_device, FALSE, FALSE))
             goto bail;
         count++;
         idp = (XF86ConfInactivePtr) idp->list.next;
@@ -1769,6 +1775,7 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum,
     XF86ConfAdaptorLinkPtr conf_adaptor;
     Bool defaultMonitor = FALSE;
     XF86ConfScreenRec local_conf_screen;
+    int i;
 
     if (!conf_screen) {
         memset(&local_conf_screen, 0, sizeof(local_conf_screen));
@@ -1811,12 +1818,20 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum,
         xf86Msg(X_DEFAULT, "No device specified for screen \"%s\".\n"
                 "\tUsing the first device section listed.\n", screenp->id);
     }
-    if (configDevice(screenp->device, conf_screen->scrn_device, TRUE)) {
+    if (configDevice(screenp->device, conf_screen->scrn_device, TRUE, FALSE)) {
         screenp->device->myScreenSection = screenp;
     }
     else {
         screenp->device = NULL;
     }
+
+    for (i = 0; i < conf_screen->num_gpu_devices; i++) {
+        screenp->gpu_devices[i] = xnfcalloc(1, sizeof(GDevRec));
+        if (configDevice(screenp->gpu_devices[i], conf_screen->scrn_gpu_devices[i], TRUE, TRUE)) {
+            screenp->gpu_devices[i]->myScreenSection = screenp;
+        }
+    }
+    screenp->num_gpu_devices = conf_screen->num_gpu_devices;
     screenp->options = conf_screen->scrn_option_lst;
 
     /*
@@ -2110,7 +2125,7 @@ configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display)
 }
 
 static Bool
-configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active)
+configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active, Bool gpu)
 {
     int i;
 
@@ -2118,10 +2133,14 @@ configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active)
         return FALSE;
     }
 
-    if (active)
-        xf86Msg(X_CONFIG, "|   |-->Device \"%s\"\n",
-                conf_device->dev_identifier);
-    else
+    if (active) {
+        if (gpu)
+            xf86Msg(X_CONFIG, "|   |-->GPUDevice \"%s\"\n",
+                    conf_device->dev_identifier);
+        else
+            xf86Msg(X_CONFIG, "|   |-->Device \"%s\"\n",
+                    conf_device->dev_identifier);
+    } else
         xf86Msg(X_CONFIG, "|-->Inactive Device \"%s\"\n",
                 conf_device->dev_identifier);
 
diff --git a/hw/xfree86/common/xf86Helper.c b/hw/xfree86/common/xf86Helper.c
index e2b32a0..7321a1a 100644
--- a/hw/xfree86/common/xf86Helper.c
+++ b/hw/xfree86/common/xf86Helper.c
@@ -1367,7 +1367,7 @@ xf86MatchDevice(const char *drivername, GDevPtr ** sectlist)
 {
     GDevPtr gdp, *pgdp = NULL;
     confScreenPtr screensecptr;
-    int i, j;
+    int i, j, k;
 
     if (sectlist)
         *sectlist = NULL;
@@ -1411,6 +1411,17 @@ xf86MatchDevice(const char *drivername, GDevPtr ** sectlist)
             pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr));
             pgdp[i++] = screensecptr->device;
         }
+        for (k = 0; k < screensecptr->num_gpu_devices; k++) {
+            if ((screensecptr->gpu_devices[k]->driver != NULL)
+            && (xf86NameCmp(screensecptr->gpu_devices[k]->driver, drivername) == 0)
+                && (!screensecptr->gpu_devices[k]->claimed)) {
+                /*
+                 * we have a matching driver that wasn't claimed, yet
+                 */
+                pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr));
+                pgdp[i++] = screensecptr->gpu_devices[k];
+            }
+        }
     }
 
     /* Then handle the inactive devices */
diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h
index 643a65d..62c0ce9 100644
--- a/hw/xfree86/common/xf86str.h
+++ b/hw/xfree86/common/xf86str.h
@@ -440,6 +440,7 @@ typedef struct _confxvadaptrec {
     void *options;
 } confXvAdaptorRec, *confXvAdaptorPtr;
 
+#define MAX_GPUDEVICES 4
 typedef struct _confscreenrec {
     const char *id;
     int screennum;
@@ -453,6 +454,9 @@ typedef struct _confscreenrec {
     int numxvadaptors;
     confXvAdaptorPtr xvadaptors;
     void *options;
+
+    int num_gpu_devices;
+    GDevPtr gpu_devices[MAX_GPUDEVICES];
 } confScreenRec, *confScreenPtr;
 
 typedef enum {
diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
index d26c3cc..e9b6d99 100644
--- a/hw/xfree86/man/xorg.conf.man
+++ b/hw/xfree86/man/xorg.conf.man
@@ -1906,6 +1906,7 @@ sections have the following format:
 .B  "Section \*qScreen\*q"
 .BI "    Identifier \*q" name \*q
 .BI "    Device     \*q" devid \*q
+.BI "    GPUDevice  \*q" devid \*q
 .BI "    Monitor    \*q" monid \*q
 .I  "    entries"
 .I  "    ..."
@@ -1949,6 +1950,18 @@ of a
 .B Device
 section in the config file.
 .TP 7
+.BI "GPUDevice  \*q" device\-id \*q
+This entry specifies the
+.B Device
+section to be used as a secondary GPU device for this screen.  When multiple graphics cards are
+present, this is what ties a specific secondary card to a screen.  The
+.I device\-id
+must match the
+.B Identifier
+of a
+.B Device
+section in the config file. This can be specified up to 4 times for a single screen.
+.TP 7
 .BI "Monitor  \*q" monitor\-id \*q
 specifies which monitor description is to be used for this screen.
 If a
diff --git a/hw/xfree86/parser/Configint.h b/hw/xfree86/parser/Configint.h
index 31035ae..e5fa6ce 100644
--- a/hw/xfree86/parser/Configint.h
+++ b/hw/xfree86/parser/Configint.h
@@ -204,6 +204,8 @@ else\
 "Multiple \"%s\" lines."
 #define MUST_BE_OCTAL_MSG \
 "The number \"%d\" given in this section must be in octal (0xxx) format."
+#define GPU_DEVICE_TOO_MANY \
+"More than %d GPU devices defined."
 
 /* Warning messages */
 #define OBSOLETE_MSG \
diff --git a/hw/xfree86/parser/Screen.c b/hw/xfree86/parser/Screen.c
index 9d8eda2..b5b454f 100644
--- a/hw/xfree86/parser/Screen.c
+++ b/hw/xfree86/parser/Screen.c
@@ -211,6 +211,7 @@ static xf86ConfigSymTabRec ScreenTab[] = {
     {DEFAULTFBBPP, "defaultfbbpp"},
     {VIRTUAL, "virtual"},
     {OPTION, "option"},
+    {GDEVICE, "gpudevice"},
     {-1, ""},
 };
 
@@ -270,6 +271,13 @@ xf86parseScreenSection(void)
                 Error(QUOTE_MSG, "Device");
             ptr->scrn_device_str = xf86_lex_val.str;
             break;
+        case GDEVICE:
+            if (xf86getSubToken(&(ptr->scrn_comment)) != STRING)
+                Error(QUOTE_MSG, "GPUDevice");
+            if (ptr->num_gpu_devices == CONF_MAXGPUDEVICES)
+                Error(GPU_DEVICE_TOO_MANY, CONF_MAXGPUDEVICES);
+            ptr->scrn_gpu_device_str[ptr->num_gpu_devices++] = xf86_lex_val.str;
+            break;
         case MONITOR:
             if (xf86getSubToken(&(ptr->scrn_comment)) != STRING)
                 Error(QUOTE_MSG, "Monitor");
@@ -342,7 +350,7 @@ xf86printScreenSection(FILE * cf, XF86ConfScreenPtr ptr)
     XF86ConfAdaptorLinkPtr aptr;
     XF86ConfDisplayPtr dptr;
     XF86ModePtr mptr;
-
+    int i;
     while (ptr) {
         fprintf(cf, "Section \"Screen\"\n");
         if (ptr->scrn_comment)
@@ -353,6 +361,9 @@ xf86printScreenSection(FILE * cf, XF86ConfScreenPtr ptr)
             fprintf(cf, "\tDriver     \"%s\"\n", ptr->scrn_obso_driver);
         if (ptr->scrn_device_str)
             fprintf(cf, "\tDevice     \"%s\"\n", ptr->scrn_device_str);
+        for (i = 0; i < ptr->num_gpu_devices; i++)
+            if (ptr->scrn_gpu_device_str[i])
+                fprintf(cf, "\tGPUDevice     \"%s\"\n", ptr->scrn_gpu_device_str[i]);
         if (ptr->scrn_monitor_str)
             fprintf(cf, "\tMonitor    \"%s\"\n", ptr->scrn_monitor_str);
         if (ptr->scrn_defaultdepth)
@@ -426,11 +437,13 @@ void
 xf86freeScreenList(XF86ConfScreenPtr ptr)
 {
     XF86ConfScreenPtr prev;
-
+    int i;
     while (ptr) {
         TestFree(ptr->scrn_identifier);
         TestFree(ptr->scrn_monitor_str);
         TestFree(ptr->scrn_device_str);
+        for (i = 0; i < ptr->num_gpu_devices; i++)
+            TestFree(ptr->scrn_gpu_device_str[i]);
         TestFree(ptr->scrn_comment);
         xf86optionListFree(ptr->scrn_option_lst);
         xf86freeAdaptorLinkList(ptr->scrn_adaptor_lst);
@@ -487,6 +500,7 @@ xf86validateScreen(XF86ConfigPtr p)
     XF86ConfScreenPtr screen = p->conf_screen_lst;
     XF86ConfMonitorPtr monitor;
     XF86ConfAdaptorLinkPtr adaptor;
+    int i;
 
     while (screen) {
         if (screen->scrn_obso_driver && !screen->scrn_identifier)
@@ -505,6 +519,10 @@ xf86validateScreen(XF86ConfigPtr p)
         screen->scrn_device =
             xf86findDevice(screen->scrn_device_str, p->conf_device_lst);
 
+        for (i = 0; i < screen->num_gpu_devices; i++) {
+            screen->scrn_gpu_devices[i] =
+                xf86findDevice(screen->scrn_gpu_device_str[i], p->conf_device_lst);
+        }
         adaptor = screen->scrn_adaptor_lst;
         while (adaptor) {
             adaptor->al_adaptor =
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 43e1755..b3a50e5 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -259,6 +259,7 @@ typedef struct {
     XF86ConfVideoAdaptorPtr al_adaptor;
 } XF86ConfAdaptorLinkRec, *XF86ConfAdaptorLinkPtr;
 
+#define CONF_MAXGPUDEVICES 4
 typedef struct {
     GenericListRec list;
     const char *scrn_identifier;
@@ -276,6 +277,10 @@ typedef struct {
     char *scrn_comment;
     int scrn_virtualX, scrn_virtualY;
     char *match_seat;
+
+    int num_gpu_devices;
+    const char *scrn_gpu_device_str[CONF_MAXGPUDEVICES];
+    XF86ConfDevicePtr scrn_gpu_devices[CONF_MAXGPUDEVICES];
 } XF86ConfScreenRec, *XF86ConfScreenPtr;
 
 typedef struct {
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index 9c44970..bbd6b90 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -143,6 +143,7 @@ typedef enum {
     /* Screen tokens */
     OBSDRIVER,
     MDEVICE,
+    GDEVICE,
     MONITOR,
     SCREENNO,
     DEFAULTDEPTH,


More information about the xorg-commit mailing list