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.veli...@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.d...@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. > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev