uterm: add PCI primary GPU detection
We used to simply probe every GPU that is reported by the kernel. However, if a system has multiple GPUs that share display controllers, we cannot use both simultaneously. Unfortunately, the kernel currently does not notify us about this. Hence, we use some heuristics to determine which GPU is the boot-gpu/primary-gpu. This only adds the detection logic, it does not modify any code to use this detection at all. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
2c5e9bff2b
commit
89e84aa78c
@ -178,6 +178,7 @@ libuterm_la_SOURCES = \
|
||||
src/uterm.h \
|
||||
src/uterm_input.h \
|
||||
src/uterm_video.h \
|
||||
src/uterm_pci.h \
|
||||
src/uterm_video.c \
|
||||
src/uterm_monitor.c \
|
||||
src/uterm_vt.c \
|
||||
@ -205,6 +206,12 @@ libuterm_la_CPPFLAGS += $(UDEV_CFLAGS)
|
||||
libuterm_la_LIBADD += $(UDEV_LIBS)
|
||||
endif
|
||||
|
||||
if BUILD_ENABLE_PCIACCESS
|
||||
libuterm_la_CPPFLAGS += $(PCIACCESS_CFLAGS)
|
||||
libuterm_la_LIBADD += $(PCIACCESS_LIBS)
|
||||
libuterm_la_SOURCES += src/uterm_pci.c
|
||||
endif
|
||||
|
||||
if BUILD_ENABLE_VIDEO_FBDEV
|
||||
libuterm_la_SOURCES += src/uterm_video_fbdev.c
|
||||
endif
|
||||
|
43
configure.ac
43
configure.ac
@ -103,6 +103,11 @@ PKG_CHECK_MODULES([FUSE], [fuse],
|
||||
AC_SUBST(FUSE_CFLAGS)
|
||||
AC_SUBST(FUSE_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES([PCIACCESS], [pciaccess],
|
||||
[have_pciaccess=yes], [have_pciaccess=no])
|
||||
AC_SUBST(PCIACCESS_CFLAGS)
|
||||
AC_SUBST(PCIACCESS_LIBS)
|
||||
|
||||
#
|
||||
# Parse arguments
|
||||
# This parses all arguments that are given via "--enable-XY" or "--with-XY" and
|
||||
@ -200,6 +205,16 @@ if test "x$enable_hotplug" = "x" ; then
|
||||
fi
|
||||
AC_MSG_RESULT([$enable_hotplug])
|
||||
|
||||
# pciaccess
|
||||
AC_MSG_CHECKING([whether user wants pciaccess device detection])
|
||||
AC_ARG_ENABLE([pciaccess],
|
||||
[AS_HELP_STRING([--enable-pciaccess],
|
||||
[enable device detection via pciaccess])])
|
||||
if test "x$enable_pciaccess" = "x" ; then
|
||||
enable_pciaccess="yes (default)"
|
||||
fi
|
||||
AC_MSG_RESULT([$enable_pciaccess])
|
||||
|
||||
# eloop-dbus
|
||||
AC_MSG_CHECKING([whether user wants eloop dbus support])
|
||||
AC_ARG_ENABLE([eloop-dbus],
|
||||
@ -455,6 +470,16 @@ if test ! "x$enable_hotplug" = "xno" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# pciaccess
|
||||
pciaccess_avail=no
|
||||
if test ! "x$enable_pciaccess" = "xno" ; then
|
||||
if test "x$have_pciaccess" = "xyes" ; then
|
||||
pciaccess_avail=yes
|
||||
elif test "x$enable_pciaccess" = "xyes" ; then
|
||||
AC_ERROR([pciaccess libraries not found for pciaccess device detection])
|
||||
fi
|
||||
fi
|
||||
|
||||
# renderer bblit
|
||||
renderer_bblit_avail=no
|
||||
if test ! "x$enable_renderer_bblit" = "xno" ; then
|
||||
@ -714,6 +739,14 @@ if test "x$renderer_bblit_avail" = "xyes" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# pciaccess
|
||||
pciaccess_enabled=no
|
||||
if test "x$pciaccess_avail" = "xyes" ; then
|
||||
if test "x${enable_pciaccess% *}" = "xyes" ; then
|
||||
pciaccess_enabled=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
# hotplug
|
||||
hotplug_enabled=no
|
||||
if test "x$hotplug_avail" = "xyes" ; then
|
||||
@ -885,6 +918,15 @@ fi
|
||||
AM_CONDITIONAL([BUILD_ENABLE_HOTPLUG],
|
||||
[test "x$hotplug_enabled" = "xyes"])
|
||||
|
||||
# pciaccess
|
||||
if test "x$pciaccess_enabled" = "xyes" ; then
|
||||
AC_DEFINE([BUILD_ENABLE_PCIACCESS], [1],
|
||||
[Use pciaccess for device detection])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([BUILD_ENABLE_PCIACCESS],
|
||||
[test "x$pciaccess_enabled" = "xyes"])
|
||||
|
||||
# renderer bblit
|
||||
if test "x$renderer_bblit_enabled" = "xyes" ; then
|
||||
AC_DEFINE([BUILD_ENABLE_RENDERER_BBLIT], [1],
|
||||
@ -1060,6 +1102,7 @@ AC_MSG_NOTICE([Build configuration:
|
||||
optimizations: $optimizations_enabled ($optimizations_avail)
|
||||
multi-seat: $multi_seat_enabled ($multi_seat_avail)
|
||||
hotplug: $hotplug_enabled ($hotplug_avail)
|
||||
pciaccess: $pciaccess_enabled ($pciaccess_avail)
|
||||
eloop-dbus: $eloop_dbus_enabled ($eloop_dbus_avail)
|
||||
|
||||
Video Backends:
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "log.h"
|
||||
#include "shl_dlist.h"
|
||||
#include "uterm.h"
|
||||
#include "uterm_pci.h"
|
||||
|
||||
#ifdef BUILD_ENABLE_MULTI_SEAT
|
||||
#include <systemd/sd-login.h>
|
||||
@ -77,6 +78,8 @@ struct uterm_monitor {
|
||||
struct ev_fd *sd_mon_fd;
|
||||
#endif
|
||||
|
||||
char *pci_primary_id;
|
||||
|
||||
struct udev *udev;
|
||||
struct udev_monitor *umon;
|
||||
struct ev_fd *umon_fd;
|
||||
@ -669,6 +672,10 @@ int uterm_monitor_new(struct uterm_monitor **out,
|
||||
mon->data = data;
|
||||
shl_dlist_init(&mon->seats);
|
||||
|
||||
ret = uterm_pci_get_primary_id(&mon->pci_primary_id);
|
||||
if (ret)
|
||||
log_warning("cannot get PCI primary ID");
|
||||
|
||||
ret = monitor_sd_init(mon);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
@ -760,6 +767,7 @@ err_udev:
|
||||
err_sd:
|
||||
monitor_sd_deinit(mon);
|
||||
err_free:
|
||||
free(mon->pci_primary_id);
|
||||
free(mon);
|
||||
return ret;
|
||||
}
|
||||
@ -791,6 +799,7 @@ void uterm_monitor_unref(struct uterm_monitor *mon)
|
||||
udev_unref(mon->udev);
|
||||
monitor_sd_deinit(mon);
|
||||
ev_eloop_unref(mon->eloop);
|
||||
free(mon->pci_primary_id);
|
||||
free(mon);
|
||||
}
|
||||
|
||||
|
213
src/uterm_pci.c
Normal file
213
src/uterm_pci.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* uterm - Linux User-Space Terminal
|
||||
*
|
||||
* Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* PCI Helpers
|
||||
* This uses the pciaccess library to retrieve information from the PCI bus.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <pciaccess.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
#include "uterm.h"
|
||||
#include "uterm_pci.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "pci"
|
||||
|
||||
/* pci classes */
|
||||
#define UTERM_PCI_CLASS_PREHISTORIC 0x00
|
||||
#define UTERM_PCI_CLASS_DISPLAY 0x03
|
||||
#define UTERM_PCI_CLASS_MULTIMEDIA 0x04
|
||||
#define UTERM_PCI_CLASS_PROCESSOR 0x0b
|
||||
|
||||
/* pci sub-classes */
|
||||
#define UTERM_PCI_SUBCLASS_DISPLAY_VGA 0x00
|
||||
#define UTERM_PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00
|
||||
#define UTERM_PCI_SUBCLASS_PROCESSOR_COPROC 0x40
|
||||
|
||||
/* pci registers */
|
||||
#define UTERM_PCI_CMD_MEM_ENABLE 0x02
|
||||
|
||||
static bool uterm_pci_is_gpu(struct pci_device *dev)
|
||||
{
|
||||
uint32_t class = dev->device_class;
|
||||
uint32_t match;
|
||||
|
||||
match = UTERM_PCI_CLASS_PREHISTORIC << 16;
|
||||
if ((class & 0x00ff0000) == match)
|
||||
return true;
|
||||
|
||||
match = UTERM_PCI_CLASS_DISPLAY << 16;
|
||||
if ((class & 0x00ff0000) == match)
|
||||
return true;
|
||||
|
||||
match = UTERM_PCI_CLASS_MULTIMEDIA << 16;
|
||||
match |= UTERM_PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8;
|
||||
if ((class & 0x00ffff00) == match)
|
||||
return true;
|
||||
|
||||
match = UTERM_PCI_CLASS_PROCESSOR << 16;
|
||||
match |= UTERM_PCI_SUBCLASS_PROCESSOR_COPROC << 8;
|
||||
if ((class & 0x00ffff00) == match)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool uterm_pci_is_vga(struct pci_device *dev)
|
||||
{
|
||||
uint32_t class = dev->device_class;
|
||||
uint32_t match;
|
||||
|
||||
match = UTERM_PCI_CLASS_DISPLAY << 16;
|
||||
match |= UTERM_PCI_SUBCLASS_DISPLAY_VGA << 8;
|
||||
return (class & 0x00ffff00) == match;
|
||||
}
|
||||
|
||||
static const struct pci_slot_match uterm_pci_match = {
|
||||
.domain = PCI_MATCH_ANY,
|
||||
.bus = PCI_MATCH_ANY,
|
||||
.dev = PCI_MATCH_ANY,
|
||||
.func = PCI_MATCH_ANY,
|
||||
.match_data = 0,
|
||||
};
|
||||
|
||||
#define UTERM_PCI_FORMAT "pci:%04x:%02x:%02x.%d"
|
||||
|
||||
int uterm_pci_get_primary_id(char **out)
|
||||
{
|
||||
int ret;
|
||||
struct pci_device_iterator *iter;
|
||||
struct pci_device *dev;
|
||||
char *buf;
|
||||
uint16_t cmd;
|
||||
unsigned int num;
|
||||
|
||||
if (!out)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_system_init();
|
||||
if (ret) {
|
||||
log_error("cannot initialize pciaccess library (%d/%d): %m",
|
||||
ret, errno);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
iter = pci_slot_match_iterator_create(&uterm_pci_match);
|
||||
if (!iter) {
|
||||
log_error("cannot create pci-slot iterator (%d): %m",
|
||||
errno);
|
||||
ret = -EFAULT;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
buf = NULL;
|
||||
num = 0;
|
||||
while ((dev = pci_device_next(iter))) {
|
||||
if (!uterm_pci_is_gpu(dev))
|
||||
continue;
|
||||
|
||||
++num;
|
||||
if (!pci_device_is_boot_vga(dev))
|
||||
continue;
|
||||
|
||||
log_debug("primary PCI GPU: " UTERM_PCI_FORMAT,
|
||||
dev->domain, dev->bus, dev->dev, dev->func);
|
||||
|
||||
if (buf) {
|
||||
log_warning("multiple primary PCI GPUs found");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = asprintf(&buf, UTERM_PCI_FORMAT, dev->domain, dev->bus,
|
||||
dev->dev, dev->func);
|
||||
if (ret < 0) {
|
||||
log_error("cannot allocate memory for PCI name");
|
||||
goto out_iter;
|
||||
}
|
||||
}
|
||||
|
||||
free(iter);
|
||||
if (buf) {
|
||||
ret = 0;
|
||||
*out = buf;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
/* If no GPU is marked as boot_vga, we try finding a VGA card */
|
||||
iter = pci_slot_match_iterator_create(&uterm_pci_match);
|
||||
if (!iter) {
|
||||
log_error("cannot create pci-slot iterator (%d): %m",
|
||||
errno);
|
||||
ret = -EFAULT;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
while ((dev = pci_device_next(iter))) {
|
||||
if (!uterm_pci_is_gpu(dev))
|
||||
continue;
|
||||
|
||||
ret = pci_device_cfg_read_u16(dev, &cmd, 4);
|
||||
if (ret)
|
||||
continue;
|
||||
if (!(cmd & UTERM_PCI_CMD_MEM_ENABLE))
|
||||
continue;
|
||||
if (num != 1 && !uterm_pci_is_vga(dev))
|
||||
continue;
|
||||
|
||||
log_debug("primary PCI VGA GPU: " UTERM_PCI_FORMAT,
|
||||
dev->domain, dev->bus, dev->dev, dev->func);
|
||||
|
||||
if (buf) {
|
||||
log_warning("multiple primary PCI VGA GPUs found");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = asprintf(&buf, UTERM_PCI_FORMAT, dev->domain, dev->bus,
|
||||
dev->dev, dev->func);
|
||||
if (ret < 0) {
|
||||
log_error("cannot allocate memory for PCI name");
|
||||
goto out_iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
ret = 0;
|
||||
*out = buf;
|
||||
} else {
|
||||
log_warning("no primary PCI GPU found");
|
||||
ret = -ENOENT;
|
||||
}
|
||||
|
||||
out_iter:
|
||||
free(iter);
|
||||
out_cleanup:
|
||||
pci_system_cleanup();
|
||||
return ret;
|
||||
}
|
50
src/uterm_pci.h
Normal file
50
src/uterm_pci.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* uterm - Linux User-Space Terminal
|
||||
*
|
||||
* Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* PCI Helpers
|
||||
* This uses the pciaccess library to retrieve information from the PCI bus.
|
||||
*/
|
||||
|
||||
#ifndef UTERM_PCI_H
|
||||
#define UTERM_PCI_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "uterm.h"
|
||||
|
||||
#ifdef BUILD_ENABLE_PCIACCESS
|
||||
|
||||
int uterm_pci_get_primary_id(char **out);
|
||||
|
||||
#else
|
||||
|
||||
static inline int uterm_pci_get_primary_id(char **out)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* UTERM_PCI_H */
|
Loading…
x
Reference in New Issue
Block a user