[Mesa-dev] [PATCH 03/11] Loader: Add gpu selection code via DRI_PRIME.
Emil Velikov
emil.l.velikov at gmail.com
Tue Jun 24 15:56:30 PDT 2014
On 19/06/14 04:27, Axel Davy wrote:
> v2: Fix the leak of device_name
> v3: Rebased
>
> It enables to use the DRI_PRIME env var to specify
> which gpu to use.
> Two syntax are supported:
> If DRI_PRIME is 1 it means: take any other gpu than the default one.
> If DRI_PRIME is the ID_PATH_TAG of a device: choose this device if
> possible.
>
> The ID_PATH_TAG is a tag filled by udev.
> You can check it with 'udevadm info' on the device node.
> For example it can be "pci-0000_01_00_0".
>
> Render-nodes need to be enabled to choose another gpu,
> and they need to have the ID_PATH_TAG advertised.
> It is possible for not very recent udev that the tag
> is not advertised for render-nodes, then
> ones need to add a file containing:
>
> SUBSYSTEM=="drm", IMPORT{builtin}="path_id"
>
> in /etc/udev/rules.d/
>
FWIW this patch and patch 05/11 are
Reviewed-by: Emil Velikov <emil.l.velikov at gmail.com>
Btw it would be great if we can nuke the gl types from the driconf code
(src/mesa/drivers/dri/common/xmlpool) although that is a completely different
cattle of fish.
-Emil
> Signed-off-by: Axel Davy <axel.davy at ens.fr>
> ---
> src/loader/loader.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/loader/loader.h | 7 ++
> 2 files changed, 192 insertions(+)
>
> diff --git a/src/loader/loader.c b/src/loader/loader.c
> index 0f26265..19d99d5 100644
> --- a/src/loader/loader.c
> +++ b/src/loader/loader.c
> @@ -70,6 +70,10 @@
> #ifdef HAVE_LIBUDEV
> #include <assert.h>
> #include <dlfcn.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <errno.h>
> #endif
> #ifdef HAVE_SYSFS
> #include <sys/stat.h>
> @@ -214,6 +218,187 @@ out:
>
> return (*chip_id >= 0);
> }
> +
> +static char *
> +get_render_node_from_id_path_tag(struct udev *udev,
> + char *id_path_tag,
> + char another_tag)
> +{
> + struct udev_device *device;
> + struct udev_enumerate *e;
> + struct udev_list_entry *entry;
> + const char *path, *id_path_tag_tmp;
> + char *path_res;
> + char found = 0;
> + UDEV_SYMBOL(struct udev_enumerate *, udev_enumerate_new,
> + (struct udev *));
> + UDEV_SYMBOL(int, udev_enumerate_add_match_subsystem,
> + (struct udev_enumerate *, const char *));
> + UDEV_SYMBOL(int, udev_enumerate_add_match_sysname,
> + (struct udev_enumerate *, const char *));
> + UDEV_SYMBOL(int, udev_enumerate_scan_devices,
> + (struct udev_enumerate *));
> + UDEV_SYMBOL(struct udev_list_entry *, udev_enumerate_get_list_entry,
> + (struct udev_enumerate *));
> + UDEV_SYMBOL(struct udev_list_entry *, udev_list_entry_get_next,
> + (struct udev_list_entry *));
> + UDEV_SYMBOL(const char *, udev_list_entry_get_name,
> + (struct udev_list_entry *));
> + UDEV_SYMBOL(struct udev_device *, udev_device_new_from_syspath,
> + (struct udev *, const char *));
> + UDEV_SYMBOL(const char *, udev_device_get_property_value,
> + (struct udev_device *, const char *));
> + UDEV_SYMBOL(const char *, udev_device_get_devnode,
> + (struct udev_device *));
> + UDEV_SYMBOL(struct udev_device *, udev_device_unref,
> + (struct udev_device *));
> +
> + e = udev_enumerate_new(udev);
> + udev_enumerate_add_match_subsystem(e, "drm");
> + udev_enumerate_add_match_sysname(e, "render*");
> +
> + udev_enumerate_scan_devices(e);
> + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
> + path = udev_list_entry_get_name(entry);
> + device = udev_device_new_from_syspath(udev, path);
> + if (!device)
> + continue;
> + id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG");
> + if (id_path_tag_tmp) {
> + if ((!another_tag && !strcmp(id_path_tag, id_path_tag_tmp)) ||
> + (another_tag && strcmp(id_path_tag, id_path_tag_tmp))) {
> + found = 1;
> + break;
> + }
> + }
> + udev_device_unref(device);
> + }
> +
> + if (found) {
> + path_res = strdup(udev_device_get_devnode(device));
> + udev_device_unref(device);
> + return path_res;
> + }
> + return NULL;
> +}
> +
> +static char *
> +get_id_path_tag_from_fd(struct udev *udev, int fd)
> +{
> + struct udev_device *device;
> + const char *id_path_tag_tmp;
> + char *id_path_tag;
> + UDEV_SYMBOL(const char *, udev_device_get_property_value,
> + (struct udev_device *, const char *));
> + UDEV_SYMBOL(struct udev_device *, udev_device_unref,
> + (struct udev_device *));
> +
> + device = udev_device_new_from_fd(udev, fd);
> + if (!device)
> + return NULL;
> +
> + id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG");
> + if (!id_path_tag_tmp)
> + return NULL;
> +
> + id_path_tag = strdup(id_path_tag_tmp);
> +
> + udev_device_unref(device);
> + return id_path_tag;
> +}
> +
> +static int
> +drm_open_device(const char *device_name)
> +{
> + int fd;
> +#ifdef O_CLOEXEC
> + fd = open(device_name, O_RDWR | O_CLOEXEC);
> + if (fd == -1 && errno == EINVAL)
> +#endif
> + {
> + fd = open(device_name, O_RDWR);
> + if (fd != -1)
> + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
> + }
> + return fd;
> +}
> +
> +int loader_get_user_preferred_fd(int default_fd, int *different_device)
> +{
> + struct udev *udev;
> + const char *dri_prime = getenv("DRI_PRIME");
> + char *prime = NULL;
> + int is_different_device = 0, fd = default_fd;
> + char *default_device_id_path_tag;
> + char *device_name = NULL;
> + char another_tag = 0;
> + UDEV_SYMBOL(struct udev *, udev_new, (void));
> + UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *));
> +
> + if (dri_prime)
> + prime = strdup(dri_prime);
> +
> + if (prime == NULL) {
> + *different_device = 0;
> + return default_fd;
> + }
> +
> + udev = udev_new();
> + if (!udev)
> + goto prime_clean;
> +
> + default_device_id_path_tag = get_id_path_tag_from_fd(udev, default_fd);
> + if (!default_device_id_path_tag)
> + goto udev_clean;
> +
> + is_different_device = 1;
> + /* two format are supported:
> + * "1": choose any other card than the card used by default.
> + * id_path_tag: (for example "pci-0000_02_00_0") choose the card
> + * with this id_path_tag.
> + */
> + if (!strcmp(prime,"1")) {
> + free(prime);
> + prime = strdup(default_device_id_path_tag);
> + /* request a card with a different card than the default card */
> + another_tag = 1;
> + } else if (!strcmp(default_device_id_path_tag, prime))
> + /* we are to get a new fd (render-node) of the same device */
> + is_different_device = 0;
> +
> + device_name = get_render_node_from_id_path_tag(udev,
> + prime,
> + another_tag);
> + if (device_name == NULL) {
> + is_different_device = 0;
> + goto default_device_clean;
> + }
> +
> + fd = drm_open_device(device_name);
> + if (fd > 0) {
> + close(default_fd);
> + } else {
> + fd = default_fd;
> + is_different_device = 0;
> + }
> + free(device_name);
> +
> + default_device_clean:
> + free(default_device_id_path_tag);
> + udev_clean:
> + udev_unref(udev);
> + prime_clean:
> + free(prime);
> +
> + *different_device = is_different_device;
> + return fd;
> +}
> +#else
> +int loader_get_user_preferred_fd(int default_fd, int *different_device)
> +{
> + *different_device = 0;
> + return default_fd;
> +}
> #endif
>
> #if defined(HAVE_SYSFS)
> diff --git a/src/loader/loader.h b/src/loader/loader.h
> index dfd77ba..fa57950 100644
> --- a/src/loader/loader.h
> +++ b/src/loader/loader.h
> @@ -41,6 +41,13 @@ loader_get_driver_for_fd(int fd, unsigned driver_types);
> char *
> loader_get_device_name_for_fd(int fd);
>
> +/* Function to get a different device than the one we are to use by default,
> + * if the user requests so and it is possible. The initial fd will be closed
> + * if neccessary. The returned fd is potentially a render-node.
> + */
> +
> +int
> +loader_get_user_preferred_fd(int default_fd, int *different_device);
>
> /* for logging.. keep this aligned with egllog.h so we can just use
> * _eglLog directly.
>
More information about the mesa-dev
mailing list