From 0af066ff25329278ed48f1a62b980f359ad3d235 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 29 Oct 2012 19:21:16 +0100 Subject: [PATCH] compositor-drm: prefer PCI boot_vga GPU over other GPUs If we can find a boot_vga PCI GPU, we should prefer it over any other GPU that is connected to the system. The boot_vga flag tells us that this GPU is the primary system GPU. This fixes problems on two-GPU-systems were the wrong GPU is used. It also fixes systems were DisplayLink GPUs are available with lower IDs than PCI GPUs (although, this seems unlikely). Note that udev_enumerate guarantees that the entry-list is sorted. So for systems that have platform-GPUs, these should almost always be reported prior to hotpluggable (PCI, USB, ...) GPUs, as the kernel probes them first. https://bugs.freedesktop.org/show_bug.cgi?id=56237 Signed-off-by: David Herrmann --- src/compositor-drm.c | 90 ++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 3e75387a..1730cb2b 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -2148,18 +2148,72 @@ switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data) tty_activate_vt(ec->tty, key - KEY_F1 + 1); } +/* + * Find primary GPU + * Some systems may have multiple DRM devices attached to a single seat. This + * function loops over all devices and tries to find a PCI device with the + * boot_vga sysfs attribute set to 1. + * If no such device is found, the first DRM device reported by udev is used. + */ +static struct udev_device* +find_primary_gpu(struct drm_compositor *ec, const char *seat) +{ + struct udev_enumerate *e; + struct udev_list_entry *entry; + const char *path, *device_seat, *id; + struct udev_device *device, *drm_device, *pci; + + e = udev_enumerate_new(ec->udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "card[0-9]*"); + + udev_enumerate_scan_devices(e); + drm_device = NULL; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(ec->udev, path); + if (!device) + continue; + device_seat = udev_device_get_property_value(device, "ID_SEAT"); + if (!device_seat) + device_seat = default_seat; + if (strcmp(device_seat, seat)) { + udev_device_unref(device); + continue; + } + + pci = udev_device_get_parent_with_subsystem_devtype(device, + "pci", NULL); + if (pci) { + id = udev_device_get_sysattr_value(pci, "boot_vga"); + if (id && !strcmp(id, "1")) { + if (drm_device) + udev_device_unref(drm_device); + drm_device = device; + break; + } + } + + if (!drm_device) + drm_device = device; + else + udev_device_unref(device); + } + + udev_enumerate_unref(e); + return drm_device; +} + static struct weston_compositor * drm_compositor_create(struct wl_display *display, int connector, const char *seat, int tty, int argc, char *argv[], const char *config_file) { struct drm_compositor *ec; - struct udev_enumerate *e; - struct udev_list_entry *entry; - struct udev_device *device, *drm_device; - const char *path, *device_seat; + struct udev_device *drm_device; struct wl_event_loop *loop; struct weston_seat *weston_seat, *next; + const char *path; uint32_t key; weston_log("initializing drm backend\n"); @@ -2188,30 +2242,12 @@ drm_compositor_create(struct wl_display *display, goto err_udev; } - e = udev_enumerate_new(ec->udev); - udev_enumerate_add_match_subsystem(e, "drm"); - udev_enumerate_add_match_sysname(e, "card[0-9]*"); - - udev_enumerate_scan_devices(e); - drm_device = NULL; - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - path = udev_list_entry_get_name(entry); - device = udev_device_new_from_syspath(ec->udev, path); - device_seat = - udev_device_get_property_value(device, "ID_SEAT"); - if (!device_seat) - device_seat = default_seat; - if (strcmp(device_seat, seat) == 0) { - drm_device = device; - break; - } - udev_device_unref(device); - } - + drm_device = find_primary_gpu(ec, seat); if (drm_device == NULL) { weston_log("no drm device found\n"); - goto err_udev_enum; + goto err_tty; } + path = udev_device_get_syspath(drm_device); if (init_egl(ec, drm_device) < 0) { weston_log("failed to initialize egl\n"); @@ -2268,7 +2304,6 @@ drm_compositor_create(struct wl_display *display, } udev_device_unref(drm_device); - udev_enumerate_unref(e); return &ec->base; @@ -2289,8 +2324,7 @@ err_sprite: destroy_sprites(ec); err_udev_dev: udev_device_unref(drm_device); -err_udev_enum: - udev_enumerate_unref(e); +err_tty: tty_destroy(ec->tty); err_udev: udev_unref(ec->udev);