[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