From a5367face12d8e4162bc49a60b5d13955a7fb293 Mon Sep 17 00:00:00 2001 From: Jacob Cherry Date: Wed, 3 Mar 2021 17:50:31 +0000 Subject: [PATCH] xfree86: Fix autoconfig secondary GPU devices The code path added by commit 69e4b8e6 (xfree86: attempt to autoconfig gpu slave devices (v3)) assumes that it will only be run if the primary device on the screen is the first device in xf86configptr->conf_device_lst. While this is true most of the time, there are two specific cases where this assumption fails. First, if the first device in conf_device_lst is assigned to a different seat than the running X server, it will be skipped by the previous FIND_SUITABLE macro usage. Second, if the primary device was explicitly assigned to the screen but auto_gpu_device is still set and no secondary devices were explicitly listed, that device may not be the first device in conf_device_lst. When the first device in conf_device_lst is not the primary device assigned to the screen, two problems emerge. First, the first device in conf_device_lst will never be assigned to the screen as a secondary device. Second, the primary device is additionally assigned to the screen as a secondary device. The combination of these problems causes certain otherwise valid configurations to be invalid. For example, if a primary device is assigned to a screen and a secondary device is listed in the config but not explicitly assigned to the screen, then one order of the device sections results in a usable PRIME or Reverse PRIME setup and the other order does not. This commit removes the assumption that the primary device is the first device in conf_device_lst by starting the loop from the start of conf_device_lst and skipping the primary device when it is encountered. Signed-off-by: Jacob Cherry --- hw/xfree86/common/xf86Config.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c index 75657fead..608f093bb 100644 --- a/hw/xfree86/common/xf86Config.c +++ b/hw/xfree86/common/xf86Config.c @@ -1738,15 +1738,34 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum, if (auto_gpu_device && conf_screen->num_gpu_devices == 0 && xf86configptr->conf_device_lst) { - XF86ConfDevicePtr sdevice = xf86configptr->conf_device_lst->list.next; + /* Loop through the entire device list and skip the primary device + * assigned to the screen. This is important because there are two + * cases where the assigned primary device is not the first device in + * the device list. Firstly, if the first device in the list is assigned + * to a different seat than this X server, it will not have been picked + * by the previous FIND_SUITABLE. Secondly, if the device was explicitly + * assigned in the config but there is still only one screen, this code + * path is executed but the explicitly assigned device may not be the + * first device in the list. */ + XF86ConfDevicePtr ptmp, sdevice = xf86configptr->conf_device_lst; 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]) + FIND_SUITABLE (XF86ConfDevicePtr, sdevice, ptmp); + if (!ptmp) break; + + /* skip the primary device on the screen */ + if (ptmp != conf_screen->scrn_device) { + conf_screen->scrn_gpu_devices[i] = ptmp; + } else { + sdevice = ptmp->list.next; + i--; /* run the next iteration with the same index */ + continue; + } + 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;