[PATCH weston 1/2] pci: add PCI helpers to detect primary GPUs

David Herrmann dh.herrmann at googlemail.com
Sat Oct 27 05:54:42 PDT 2012


This adds one global helper which returns a string describing the primary
PCI GPU. This string can later be used to compare with drmGetBusid() to
check whether a given DRM GPU is the primary GPU.

This layer is disabled if weston is compiled without libpciaccess. The
heuristics are very similar to the heuristics in the xserver but avoid all
the heavy book-keeping as we are not interested in any other PCI stuff.

Signed-off-by: David Herrmann <dh.herrmann at googlemail.com>
---
 configure.ac    |   8 +++
 src/Makefile.am |   7 ++
 src/pci.c       | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)
 create mode 100644 src/pci.c

diff --git a/configure.ac b/configure.ac
index 0f34a7e..6103ab0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -129,6 +129,14 @@ else
   cairo_modules="cairo-gl"
 fi
 
+PKG_CHECK_MODULES(PCIACCESS, [pciaccess],
+                  [have_pciaccess=yes], [have_pciaccess=no])
+AS_IF([test "x$have_pciaccess" = "xyes"],
+      [AC_DEFINE([HAVE_PCIACCESS], [1], [Have libpciaccess])])
+AM_CONDITIONAL(HAVE_PCIACCESS, test x$have_pciaccess = xyes)
+AC_SUBST(PCIACCESS_CFLAGS)
+AC_SUBST(PCIACCESS_LIBS)
+
 PKG_CHECK_MODULES(PIXMAN, [pixman-1])
 PKG_CHECK_MODULES(PNG, [libpng])
 PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])
diff --git a/src/Makefile.am b/src/Makefile.am
index acc2415..a405671 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -111,6 +111,13 @@ drm_backend_la_SOURCES =			\
 	launcher-util.h				\
 	libbacklight.c				\
 	libbacklight.h
+
+if HAVE_PCIACCESS
+drm_backend_la_SOURCES += pci.c
+drm_backend_la_CFLAGS += $(PCIACCESS_CFLAGS)
+drm_backend_la_LIBADD += $(PCIACCESS_LIBS)
+endif
+
 endif
 
 if ENABLE_WAYLAND_COMPOSITOR
diff --git a/src/pci.c b/src/pci.c
new file mode 100644
index 0000000..7f42323
--- /dev/null
+++ b/src/pci.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2012 David Herrmann <dh.herrmann at googlemail.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pciaccess.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "compositor.h"
+
+char *weston_pci_get_primary_id(void);
+
+/* pci classes */
+#define WESTON_PCI_CLASS_PREHISTORIC		0x00
+#define WESTON_PCI_CLASS_DISPLAY		0x03
+#define WESTON_PCI_CLASS_MULTIMEDIA		0x04
+#define WESTON_PCI_CLASS_PROCESSOR		0x0b
+
+/* pci sub-classes */
+#define WESTON_PCI_SUBCLASS_DISPLAY_VGA		0x00
+#define WESTON_PCI_SUBCLASS_MULTIMEDIA_VIDEO	0x00
+#define WESTON_PCI_SUBCLASS_PROCESSOR_COPROC	0x40
+
+/* pci registers */
+#define WESTON_PCI_CMD_MEM_ENABLE		0x02
+
+static bool weston_pci_is_gpu(struct pci_device *dev)
+{
+	uint32_t class = dev->device_class;
+	uint32_t match;
+
+	match = WESTON_PCI_CLASS_PREHISTORIC << 16;
+	if ((class & 0x00ff0000) == match)
+		return true;
+
+	match = WESTON_PCI_CLASS_DISPLAY << 16;
+	if ((class & 0x00ff0000) == match)
+		return true;
+
+	match = WESTON_PCI_CLASS_MULTIMEDIA << 16;
+	match |= WESTON_PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8;
+	if ((class & 0x00ffff00) == match)
+		return true;
+
+	match = WESTON_PCI_CLASS_PROCESSOR << 16;
+	match |= WESTON_PCI_SUBCLASS_PROCESSOR_COPROC << 8;
+	if ((class & 0x00ffff00) == match)
+		return true;
+
+	return false;
+}
+
+static bool weston_pci_is_vga(struct pci_device *dev)
+{
+	uint32_t class = dev->device_class;
+	uint32_t match;
+
+	match = WESTON_PCI_CLASS_DISPLAY << 16;
+	match |= WESTON_PCI_SUBCLASS_DISPLAY_VGA << 8;
+	return (class & 0x00ffff00) == match;
+}
+
+static const struct pci_slot_match weston_pci_match = {
+	.domain = PCI_MATCH_ANY,
+	.bus = PCI_MATCH_ANY,
+	.dev = PCI_MATCH_ANY,
+	.func = PCI_MATCH_ANY,
+	.match_data = 0,
+};
+
+#define WESTON_PCI_FORMAT "pci:%04x:%02x:%02x.%d"
+
+char *weston_pci_get_primary_id(void)
+{
+	int ret;
+	struct pci_device_iterator *iter;
+	struct pci_device *dev;
+	char *buf = NULL;
+	uint16_t cmd;
+	unsigned int num;
+
+	ret = pci_system_init();
+	if (ret) {
+		weston_log("cannot initialize pciaccess library (%d/%d): %m\n",
+			   ret, errno);
+		return NULL;
+	}
+
+	iter = pci_slot_match_iterator_create(&weston_pci_match);
+	if (!iter) {
+		weston_log("cannot create pci-slot iterator (%d): %m\n",
+			   errno);
+		goto out_cleanup;
+	}
+
+	num = 0;
+	while ((dev = pci_device_next(iter))) {
+		if (!weston_pci_is_gpu(dev))
+			continue;
+
+		++num;
+		if (!pci_device_is_boot_vga(dev))
+			continue;
+
+		weston_log("primary PCI GPU: " WESTON_PCI_FORMAT "\n",
+			   dev->domain, dev->bus, dev->dev, dev->func);
+
+		if (buf) {
+			weston_log("multiple primary PCI GPUs found\n");
+			continue;
+		}
+
+		ret = asprintf(&buf, WESTON_PCI_FORMAT, dev->domain, dev->bus,
+			       dev->dev, dev->func);
+		if (ret < 0) {
+			weston_log("cannot allocate memory for PCI name\n");
+			goto out_iter;
+		}
+	}
+
+	free(iter);
+	if (buf)
+		goto out_cleanup;
+
+	/* If no GPU is marked as boot_vga, we try finding a VGA card */
+	iter = pci_slot_match_iterator_create(&weston_pci_match);
+	if (!iter) {
+		weston_log("cannot create pci-slot iterator (%d): %m\n",
+			   errno);
+		goto out_cleanup;
+	}
+
+	while ((dev = pci_device_next(iter))) {
+		if (!weston_pci_is_gpu(dev))
+			continue;
+
+		ret = pci_device_cfg_read_u16(dev, &cmd, 4);
+		if (ret)
+			continue;
+		if (!(cmd & WESTON_PCI_CMD_MEM_ENABLE))
+			continue;
+		if (num != 1 && !weston_pci_is_vga(dev))
+			continue;
+
+		weston_log("primary PCI VGA GPU: " WESTON_PCI_FORMAT "\n",
+			   dev->domain, dev->bus, dev->dev, dev->func);
+
+		if (buf) {
+			weston_log("multiple primary PCI VGA GPUs found\n");
+			continue;
+		}
+
+		ret = asprintf(&buf, WESTON_PCI_FORMAT, dev->domain, dev->bus,
+			       dev->dev, dev->func);
+		if (ret < 0) {
+			weston_log("cannot allocate memory for PCI name\n");
+			goto out_iter;
+		}
+	}
+
+	if (!buf)
+		weston_log("no primary PCI GPU found\n");
+
+out_iter:
+	free(iter);
+out_cleanup:
+	pci_system_cleanup();
+	return buf;
+}
-- 
1.8.0



More information about the wayland-devel mailing list