loader: add optional /sys filesystem method for PCI identification.

Introduce a simple PCI identification method of looking up the answer
the /sys filesystem (available on Linux).  Attempted after libudev, but
before DRM.

Disabled by default (available only when the --enable-sysfs configure
option is specified).

Signed-off-by: Gary Wong <gtw@gnu.org>
Acked-by: Emil Velikov <emil.l.velikov@gmail.com>
This commit is contained in:
Gary Wong 2014-05-21 21:07:42 -06:00
parent 090c772b8a
commit 85b6f36ca5
2 changed files with 137 additions and 11 deletions

View File

@ -870,14 +870,21 @@ fi
case "$host_os" in
linux*)
need_libudev=yes ;;
need_pci_id=yes ;;
*)
need_libudev=no ;;
need_pci_id=no ;;
esac
PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED],
have_libudev=yes, have_libudev=no)
AC_ARG_ENABLE([sysfs],
[AS_HELP_STRING([--enable-sysfs],
[enable /sys PCI identification @<:@default=disabled@:>@])],
[have_sysfs="$enableval"],
[have_sysfs=no]
)
if test "x$enable_dri" = xyes; then
if test "$enable_static" = yes; then
AC_MSG_ERROR([Cannot use static libraries for DRI drivers])
@ -973,8 +980,15 @@ xyesno)
;;
esac
have_pci_id=no
if test "$have_libudev" = yes; then
DEFINES="$DEFINES -DHAVE_LIBUDEV"
have_pci_id=yes
fi
if test "$have_sysfs" = yes; then
DEFINES="$DEFINES -DHAVE_SYSFS"
have_pci_id=yes
fi
# This is outside the case (above) so that it is invoked even for non-GLX
@ -1076,8 +1090,8 @@ if test "x$enable_dri" = xyes; then
DEFINES="$DEFINES -DHAVE_DRI3"
fi
if test "x$have_libudev" != xyes; then
AC_MSG_ERROR([libudev-dev required for building DRI])
if test "x$have_pci_id" != xyes; then
AC_MSG_ERROR([libudev-dev or sysfs required for building DRI])
fi
case "$host_cpu" in
@ -1252,8 +1266,8 @@ if test "x$enable_gbm" = xauto; then
esac
fi
if test "x$enable_gbm" = xyes; then
if test "x$need_libudev$have_libudev" = xyesno; then
AC_MSG_ERROR([gbm requires udev >= $LIBUDEV_REQUIRED])
if test "x$need_pci_id$have_pci_id" = xyesno; then
AC_MSG_ERROR([gbm requires udev >= $LIBUDEV_REQUIRED or sysfs])
fi
if test "x$enable_dri" = xyes; then
@ -1271,7 +1285,7 @@ if test "x$enable_gbm" = xyes; then
fi
fi
AM_CONDITIONAL(HAVE_GBM, test "x$enable_gbm" = xyes)
if test "x$need_libudev" = xyes; then
if test "x$need_pci_id$have_libudev" = xyesyes; then
GBM_PC_REQ_PRIV="libudev >= $LIBUDEV_REQUIRED"
else
GBM_PC_REQ_PRIV=""
@ -1560,9 +1574,9 @@ for plat in $egl_platforms; do
;;
esac
case "$plat$need_libudev$have_libudev" in
case "$plat$need_pci_id$have_pci_id" in
waylandyesno|drmyesno)
AC_MSG_ERROR([cannot build $plat platform without udev >= $LIBUDEV_REQUIRED]) ;;
AC_MSG_ERROR([cannot build $plat platform without udev >= $LIBUDEV_REQUIRED or sysfs]) ;;
esac
done
@ -1843,8 +1857,8 @@ gallium_require_llvm() {
gallium_require_drm_loader() {
if test "x$enable_gallium_loader" = xyes; then
if test "x$need_libudev$have_libudev" = xyesno; then
AC_MSG_ERROR([Gallium drm loader requires libudev >= $LIBUDEV_REQUIRED])
if test "x$need_pci_id$have_pci_id" = xyesno; then
AC_MSG_ERROR([Gallium drm loader requires libudev >= $LIBUDEV_REQUIRED or sysfs])
fi
if test "x$have_libdrm" != xyes; then
AC_MSG_ERROR([Gallium drm loader requires libdrm >= $LIBDRM_REQUIRED])

View File

@ -71,6 +71,10 @@
#include <assert.h>
#include <dlfcn.h>
#endif
#ifdef HAVE_SYSFS
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include "loader.h"
#ifndef __NOT_HAVE_DRM_H
@ -212,6 +216,66 @@ out:
}
#endif
#if defined(HAVE_SYSFS)
static int
dev_node_from_fd(int fd, unsigned int *maj, unsigned int *min)
{
struct stat buf;
if (fstat(fd, &buf) < 0) {
log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd);
return -1;
}
if (!S_ISCHR(buf.st_mode)) {
log_(_LOADER_WARNING, "MESA-LOADER: fd %d not a character device\n", fd);
return -1;
}
*maj = major(buf.st_rdev);
*min = minor(buf.st_rdev);
return 0;
}
static int
sysfs_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
{
unsigned int maj, min;
FILE *f;
char buf[0x40];
if (dev_node_from_fd(fd, &maj, &min) < 0) {
*chip_id = -1;
return 0;
}
snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/vendor", maj, min);
if (!(f = fopen(buf, "r"))) {
*chip_id = -1;
return 0;
}
if (fscanf(f, "%x", vendor_id) != 1) {
*chip_id = -1;
fclose(f);
return 0;
}
fclose(f);
snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/device", maj, min);
if (!(f = fopen(buf, "r"))) {
*chip_id = -1;
return 0;
}
if (fscanf(f, "%x", chip_id) != 1) {
*chip_id = -1;
fclose(f);
return 0;
}
fclose(f);
return 1;
}
#endif
#if !defined(__NOT_HAVE_DRM_H)
/* for i915 */
#include <i915_drm.h>
@ -291,6 +355,10 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
if (libudev_get_pci_id_for_fd(fd, vendor_id, chip_id))
return 1;
#endif
#if HAVE_SYSFS
if (sysfs_get_pci_id_for_fd(fd, vendor_id, chip_id))
return 1;
#endif
#if !defined(__NOT_HAVE_DRM_H)
if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id))
return 1;
@ -332,6 +400,46 @@ out:
#endif
#if HAVE_SYSFS
static char *
sysfs_get_device_name_for_fd(int fd)
{
char *device_name = NULL;
unsigned int maj, min;
FILE *f;
char buf[0x40];
static const char match[9] = "\0DEVNAME=";
int expected = 1;
if (dev_node_from_fd(fd, &maj, &min) < 0)
return NULL;
snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/uevent", maj, min);
if (!(f = fopen(buf, "r")))
return NULL;
while (expected < sizeof(match)) {
int c = getc(f);
if (c == EOF) {
fclose(f);
return NULL;
} else if (c == match[expected] )
expected++;
else
expected = 0;
}
strcpy(buf, "/dev/");
if (fgets(buf + 5, sizeof(buf) - 5, f))
device_name = strdup(buf);
fclose(f);
return device_name;
}
#endif
char *
loader_get_device_name_for_fd(int fd)
{
@ -340,6 +448,10 @@ loader_get_device_name_for_fd(int fd)
#if HAVE_LIBUDEV
if ((result = libudev_get_device_name_for_fd(fd)))
return result;
#endif
#if HAVE_SYSFS
if ((result = sysfs_get_device_name_for_fd(fd)))
return result;
#endif
return result;
}