[PATCH i-g-t v4] tools/mk_detect_intel_gpu: add a tool to detect Intel GPUs from their PCI IDs

Jani Nikula jani.nikula at intel.com
Wed May 22 12:54:10 UTC 2024


On Wed, 22 May 2024, Mauro Carvalho Chehab <mauro.chehab at linux.intel.com> wrote:
> From: Mauro Carvalho Chehab <mchehab at kernel.org>
>
> Such tool parses the Kernel drivers for both i915 and Xe and
> generates a script that helps detecting Intel GPU models.

I acknowledge the usefulness of such a tool, but to be brutally honest,
this implementation is horrible in so many levels.

IGT uses meson and avoids perl.

This has a makefile with perl to generate a header that's included in a
C program that is built and executed to generate a perl script that's
then the tool, and the generated perl script runs lspci(8).

I think there's really only one reasonable way to implement this in the
IGT context, and that's pure C, leveraging all the stuff in IGT, using
the PCI IDs listed in the IGT repo.

Or you can turn this into a separate pet project, because what you have
here does not fit IGT.

The i915_pciids.h parsing below is already stale, and you really can't
expect to get this merged and be kept up-to-date by folks updating
i915_pciids.h. IMO it's not maintainable.


BR,
Jani.


>
> Signed-off-by: Mauro Carvalho Chehab <mchehab at kernel.org>
> ---
>  tools/mk_detect_intel_gpu/Makefile  |  57 ++++++++
>  tools/mk_detect_intel_gpu/get_gpu.c | 216 ++++++++++++++++++++++++++++
>  2 files changed, 273 insertions(+)
>  create mode 100644 tools/mk_detect_intel_gpu/Makefile
>  create mode 100644 tools/mk_detect_intel_gpu/get_gpu.c
>
> diff --git a/tools/mk_detect_intel_gpu/Makefile b/tools/mk_detect_intel_gpu/Makefile
> new file mode 100644
> index 000000000000..ea24307ce19c
> --- /dev/null
> +++ b/tools/mk_detect_intel_gpu/Makefile
> @@ -0,0 +1,57 @@
> +# SPDX-License-Identifier: MIT
> +#
> +# Copyright © 2022-2024 Intel Corporation
> +# Author: Mauro Carvalho Chehab <mchehab at kernel.org>
> +#
> +# Usage: specify either:
> +#  make KERNEL_DIR=<directory to copy files for both i915 and Xe Intel drivers>
> +# or:
> +#  make XE_DIR=<directory to copy files for Xe Intel driver> I915_DIR=<directory to copy files for i915 Intel driver>
> +
> +XE_DIR :=
> +I915_DIR :=
> +
> +all: intel_detect_gpu.pl
> +
> +clean:
> +	rm i915_pciids.h i915_id.h xe_pciids.h xe_pci.c get_gpu intel_detect_gpu.pl
> +
> +ifneq ($(KERNEL_DIR),)
> +  XE_DIR := $(KERNEL_DIR)
> +  I915_DIR := $(KERNEL_DIR)
> +endif
> +
> +ifeq ($(XE_DIR),)
> +  $(error Need a directory with the XE driver)
> +endif
> +
> +ifeq ($(I915_DIR),)
> +  $(error Need a directory with the i915 driver)
> +endif
> +
> +intel_detect_gpu.pl: get_gpu
> +	./get_gpu >intel_detect_gpu.pl
> +	chmod 755 intel_detect_gpu.pl
> +
> +i915_pciids.h:
> +	cp ${I915_DIR}/include/drm/i915_pciids.h .
> +	sed s,"(unsigned long) info }","info }", -i i915_pciids.h
> +
> +xe_pci_ids.h:
> +	cp ${XE_DIR}/include/drm/xe_pciids.h .
> +
> +xe_pci.c:
> +	cp ${XE_DIR}/drivers/gpu/drm/xe/xe_pci.c .
> +
> +i915_id.h: i915_pciids.h xe_pci.c
> +	echo "static struct pci_device_id pci_ids[] = {" > i915_id.h
> +	tac i915_pciids.h |grep define|perl -ne 'if (/define\s+INTEL_(\w+)_IDS/) { print "\tINTEL_$$1_IDS(\"$$1\"),\n" }' >> i915_id.h
> +
> +	cat xe_pci.c|perl -ne 'if (m/(XE_)([\w_]+)(_IDS\(INTEL_VGA_DEVICE)/) { print "\t$$1$$2$$3, \"$$2\"),\n"}' >> i915_id.h
> +
> +	echo "};" >> i915_id.h
> +
> +get_gpu: get_gpu.c i915_id.h i915_pciids.h xe_pci_ids.h
> +	gcc -g -Wall get_gpu.c -o get_gpu
> +
> +.PHONY: i915_id.h i915_pciids.h
> diff --git a/tools/mk_detect_intel_gpu/get_gpu.c b/tools/mk_detect_intel_gpu/get_gpu.c
> new file mode 100644
> index 000000000000..44fee08d398b
> --- /dev/null
> +++ b/tools/mk_detect_intel_gpu/get_gpu.c
> @@ -0,0 +1,216 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2022-2024 Intel Corporation
> + * Author: Mauro Carvalho Chehab <mchehab at kernel.org>
> + */
> +
> +
> +#include "i915_pciids.h"
> +#include "xe_pciids.h"
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +
> +struct pci_device_id {
> +	unsigned int vendor, device;
> +	unsigned int subvendor, subdevice;
> +	unsigned int class, class_mask;
> +	char *name;
> +};
> +
> +#include "i915_id.h"
> +
> +#define ARRAY_SIZE(arr) sizeof(arr)/sizeof(*arr)
> +
> +#define TGL "TGL_12"
> +
> +int cmpfunc (const void *_a, const void *_b) {
> +        int ret;
> +
> +        const struct pci_device_id *a = _a;
> +        const struct pci_device_id *b = _b;
> +
> +        ret = strcmp(a->name, b->name);
> +        if (ret)
> +                return ret;
> +
> +        ret = a->vendor - b->vendor;
> +        if (ret)
> +                return ret;
> +
> +        ret = a->device - b->device;
> +        if (ret)
> +                return ret;
> +
> +        ret = a->subvendor - b->subvendor;
> +        if (ret)
> +                return ret;
> +
> +        ret = a->subdevice - b->subdevice;
> +        if (ret)
> +                return ret;
> +
> +        ret = a->class - b->class;
> +        if (ret)
> +                return ret;
> +
> +        ret = a->class_mask - b->class_mask;
> +
> +        return ret;
> +}
> +
> +
> +int main(void)
> +{
> +	int i;
> +	int shown[0x10000] = { [0 ... 0xffff] = -1 };
> +	int ignore[ARRAY_SIZE(pci_ids)] = { 0 };
> +	int other[ARRAY_SIZE(pci_ids)] = { [0 ... ARRAY_SIZE(pci_ids) - 1] = -1 };
> +	char last[80] = "";
> +
> +	printf("#!/usr/bin/perl\n\n");
> +	printf("$ENV{'LC_ALL'} = 'C';\n\n");
> +
> +        qsort(pci_ids, ARRAY_SIZE(pci_ids), sizeof(*pci_ids), cmpfunc);
> +
> +	/*
> +	 * Step 1: Handle non-subvendor specific devices, discovering duplicates
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(pci_ids); i++) {
> +		if (pci_ids[i].subvendor != (unsigned int)-1)
> +			continue;
> +
> +		if (!strncmp(pci_ids[i].name, TGL, strlen(TGL))) {
> +			char *tmp = strdup(pci_ids[i].name);
> +			pci_ids[i].name = tmp;
> +			strcpy(pci_ids[i].name + 3, tmp + strlen(TGL));
> +		}
> +
> +		if (shown[pci_ids[i].device] >= 0) {
> +			ignore[i] = i;
> +
> +                        // If it is duplicated, just ignore it
> +                        if (!cmpfunc(&pci_ids[i], &pci_ids[shown[pci_ids[i].device]]))
> +                                continue;
> +
> +			fprintf(stderr, "PCI ID: %04x:%04x %s is a subtype of %s\n",
> +			        pci_ids[i].vendor, pci_ids[i].device,
> +			        pci_ids[i].name,
> +				pci_ids[shown[pci_ids[i].device]].name);
> +
> +			other[shown[pci_ids[i].device]] = i;
> +			continue;
> +		}
> +		shown[pci_ids[i].device] = i;
> +
> +		if (pci_ids[i].device == 0x56c0)
> +			pci_ids[i].name = "ATS_M1";
> +
> +		if (pci_ids[i].device == 0x56c1)
> +			pci_ids[i].name = "ATS_M3";
> +
> +		fprintf(stderr, "Adding: %s: vendor: %04x:%04x\n",
> +		        pci_ids[i].name,
> +		        pci_ids[i].vendor, pci_ids[i].device);
> +	}
> +
> +	/*
> +	 * Step 2: output array with all other devices
> +	 */
> +	printf("my %%intel_pci_id = (");
> +
> +	for (i = 0; i < ARRAY_SIZE(pci_ids); i++) {
> +		if (ignore[i] > 0)
> +			continue;
> +
> +		if (strcmp(last, pci_ids[i].name)) {
> +			strcpy(last, pci_ids[i].name);
> +			printf("\n");
> +		}
> +
> +		printf("\t\"%04x:%04x\" => \"%s\",\n",
> +		       pci_ids[i].vendor, pci_ids[i].device,
> +		       pci_ids[i].name
> +		);
> +	}
> +	printf(");\n\n");
> +
> +	/*
> +	 * Step 3: output array with all other devices
> +	 */
> +	printf("my %%intel_pci_id_alt_name = (");
> +
> +	last[0] = '\0';
> +	for (i = 0; i < ARRAY_SIZE(pci_ids); i++) {
> +		if (ignore[i] > 0)
> +			continue;
> +
> +		if (other[i] < 0)
> +			continue;
> +
> +		if (strcmp(last, pci_ids[i].name)) {
> +			strcpy(last, pci_ids[i].name);
> +			printf("\n\t# %s alternative names\n", pci_ids[i].name);
> +		}
> +
> +		printf("\t\"%04x:%04x\" => \"%s\",\n",
> +		       pci_ids[i].vendor, pci_ids[i].device,
> +		       pci_ids[other[i]].name
> +		);
> +	}
> +	printf(");\n\n");
> +
> +	/*
> +	 * Step 4: output array for devices with subvendor/subdevice
> +	 */
> +	printf("my %%intel_pci_subvendor_id = (\n");
> +
> +	for (i = 0; i < ARRAY_SIZE(pci_ids); i++) {
> +		if (pci_ids[i].subvendor == (unsigned int) -1)
> +			continue;
> +
> +		fprintf(stderr, "Adding: %s: vendor: %04x:%04x, subvendor: %04x:%04x\n",
> +		        pci_ids[i].name,
> +		        pci_ids[i].vendor, pci_ids[i].device,
> +		        pci_ids[i].subvendor, pci_ids[i].subdevice);
> +
> +		printf("\t\"%04x:%04x %04x:%04x\" => \"%s\",\n",
> +		       pci_ids[i].vendor, pci_ids[i].device,
> +		       pci_ids[i].subvendor, pci_ids[i].subdevice,
> +		       pci_ids[i].name
> +		);
> +
> +		ignore[i] = 1;
> +	}
> +	printf(");\n\n");
> +
> +	printf("sub fix_id($) {\n");
> +	printf("\tmy $id = shift;\n");
> +	printf("\t$id = $intel_pci_id{$id} if defined($intel_pci_id{$id});\n");
> +	printf("\treturn $id;\n}\n\n");
> +	printf("my @gpus;\n");
> +	printf("my $id;\n\n");
> +	printf("open IN, \"lspci -nm|\";\n");
> +	printf("while (<IN>) {\n");
> +	printf("\tif (m/\"(8086)\"\\s\"([\\da-f]+)\".*\"([^\\\"]*)\"\\s\"([^\\\"]*\")/) {\n");
> +	printf("\t\tmy $pci_id_sub = \"$1:$2 $3:$4\";\n");
> +	printf("\t\tmy $pci_id = \"$1:$2\";\n");
> +	printf("\t\tif (defined($intel_pci_subvendor_id{$pci_id_sub})) {\n");
> +	printf("\t\t\t$id = $intel_pci_subvendor_id{$pci_id};\n");
> +	printf("\t\t} elsif (defined($intel_pci_id{$pci_id})) {\n");
> +	printf("\t\t\t$id = $intel_pci_id{$pci_id};\n");
> +	printf("\t\t}\n");
> +	printf("\t\tif ($id) {\n");
> +	printf("\t\t\tmy $subtype = \"\";\n");
> +	printf("\t\t\t$subtype = \" (\" . $intel_pci_id_alt_name{$pci_id} .\")\" if defined($intel_pci_id_alt_name{$pci_id});\n");
> +	printf("\t\t\tprint \"Detected GPU PCI device: $id$subtype, PCI ID: $pci_id\\n\";\n");
> +	printf("\t\t\tundef($id);\n");
> +	printf("\t\t\tpush @gpus, $id;\n\t\t}\n\t}\n}\n");
> +	printf("close IN;\n\n");
> +	printf("if (@gpus == 0) {\n");
> +	printf("\tprint STDERR \"Warning: No Intel GPUs detected.\\n\";\n");
> +	printf("} elsif (@gpus > 1) {\n");
> +	printf("\tprint STDERR \"Warning: More than one Intel GPUs detected.\\n\";\n");
> +	printf("}\n");
> +}

-- 
Jani Nikula, Intel


More information about the igt-dev mailing list