2 * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
3 * Copyright (C) 2014-2016 Emil Velikov <emil.l.velikov@gmail.com>
4 * Copyright (C) 2016 Intel Corporation
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * Rob Clark <robclark@freedesktop.org>
39 #include <sys/mkdev.h>
41 #ifdef MAJOR_IN_SYSMACROS
42 #include <sys/sysmacros.h>
49 #include "util/xmlconfig.h"
50 #include "util/xmlpool.h"
55 #include "pci_id_driver_map.h"
57 static void default_logger(int level
, const char *fmt
, ...)
59 if (level
<= _LOADER_WARNING
) {
62 vfprintf(stderr
, fmt
, args
);
67 static void (*log_
)(int level
, const char *fmt
, ...) = default_logger
;
70 loader_open_device(const char *device_name
)
74 fd
= open(device_name
, O_RDWR
| O_CLOEXEC
);
75 if (fd
== -1 && errno
== EINVAL
)
78 fd
= open(device_name
, O_RDWR
);
80 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
85 #if defined(HAVE_LIBDRM)
87 static const char __driConfigOptionsLoader
[] =
89 DRI_CONF_SECTION_INITIALIZATION
90 DRI_CONF_DEVICE_ID_PATH_TAG()
94 static char *loader_get_dri_config_device_id(void)
96 driOptionCache defaultInitOptions
;
97 driOptionCache userInitOptions
;
100 driParseOptionInfo(&defaultInitOptions
, __driConfigOptionsLoader
);
101 driParseConfigFiles(&userInitOptions
, &defaultInitOptions
, 0, "loader");
102 if (driCheckOption(&userInitOptions
, "device_id", DRI_STRING
))
103 prime
= strdup(driQueryOptionstr(&userInitOptions
, "device_id"));
104 driDestroyOptionCache(&userInitOptions
);
105 driDestroyOptionInfo(&defaultInitOptions
);
111 static char *drm_construct_id_path_tag(drmDevicePtr device
)
115 if (device
->bustype
== DRM_BUS_PCI
) {
116 if (asprintf(&tag
, "pci-%04x_%02x_%02x_%1u",
117 device
->businfo
.pci
->domain
,
118 device
->businfo
.pci
->bus
,
119 device
->businfo
.pci
->dev
,
120 device
->businfo
.pci
->func
) < 0) {
123 } else if (device
->bustype
== DRM_BUS_PLATFORM
||
124 device
->bustype
== DRM_BUS_HOST1X
) {
125 char *fullname
, *name
, *address
;
127 if (device
->bustype
== DRM_BUS_PLATFORM
)
128 fullname
= device
->businfo
.platform
->fullname
;
130 fullname
= device
->businfo
.host1x
->fullname
;
132 name
= strrchr(fullname
, '/');
134 name
= strdup(fullname
);
136 name
= strdup(name
+ 1);
138 address
= strchr(name
, '@');
142 if (asprintf(&tag
, "platform-%s_%s", address
, name
) < 0)
145 if (asprintf(&tag
, "platform-%s", name
) < 0)
154 static bool drm_device_matches_tag(drmDevicePtr device
, const char *prime_tag
)
156 char *tag
= drm_construct_id_path_tag(device
);
162 ret
= strcmp(tag
, prime_tag
);
168 static char *drm_get_id_path_tag_for_fd(int fd
)
173 if (drmGetDevice2(fd
, 0, &device
) != 0)
176 tag
= drm_construct_id_path_tag(device
);
177 drmFreeDevice(&device
);
181 int loader_get_user_preferred_fd(int default_fd
, bool *different_device
)
183 /* Arbitrary "maximum" value of drm devices. */
184 #define MAX_DRM_DEVICES 32
185 const char *dri_prime
= getenv("DRI_PRIME");
186 char *default_tag
, *prime
= NULL
;
187 drmDevicePtr devices
[MAX_DRM_DEVICES
];
188 int i
, num_devices
, fd
;
192 prime
= strdup(dri_prime
);
195 prime
= loader_get_dri_config_device_id();
199 *different_device
= false;
203 default_tag
= drm_get_id_path_tag_for_fd(default_fd
);
204 if (default_tag
== NULL
)
207 num_devices
= drmGetDevices2(0, devices
, MAX_DRM_DEVICES
);
211 /* two format are supported:
212 * "1": choose any other card than the card used by default.
213 * id_path_tag: (for example "pci-0000_02_00_0") choose the card
214 * with this id_path_tag.
216 if (!strcmp(prime
,"1")) {
217 /* Hmm... detection for 2-7 seems to be broken. Oh well ...
218 * Pick the first render device that is not our own.
220 for (i
= 0; i
< num_devices
; i
++) {
221 if (devices
[i
]->available_nodes
& 1 << DRM_NODE_RENDER
&&
222 !drm_device_matches_tag(devices
[i
], default_tag
)) {
229 for (i
= 0; i
< num_devices
; i
++) {
230 if (devices
[i
]->available_nodes
& 1 << DRM_NODE_RENDER
&&
231 drm_device_matches_tag(devices
[i
], prime
)) {
240 drmFreeDevices(devices
, num_devices
);
244 fd
= loader_open_device(devices
[i
]->nodes
[DRM_NODE_RENDER
]);
245 drmFreeDevices(devices
, num_devices
);
251 *different_device
= !!strcmp(default_tag
, prime
);
258 *different_device
= false;
265 int loader_get_user_preferred_fd(int default_fd
, bool *different_device
)
267 *different_device
= false;
272 #if defined(HAVE_LIBDRM)
275 drm_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
280 if (drmGetDevice2(fd
, 0, &device
) == 0) {
281 if (device
->bustype
== DRM_BUS_PCI
) {
282 *vendor_id
= device
->deviceinfo
.pci
->vendor_id
;
283 *chip_id
= device
->deviceinfo
.pci
->device_id
;
287 log_(_LOADER_DEBUG
, "MESA-LOADER: device is not located on the PCI bus\n");
290 drmFreeDevice(&device
);
293 log_(_LOADER_WARNING
, "MESA-LOADER: failed to retrieve device information\n");
303 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
306 if (drm_get_pci_id_for_fd(fd
, vendor_id
, chip_id
))
313 loader_get_device_name_for_fd(int fd
)
318 result
= drmGetDeviceNameFromFd2(fd
);
325 loader_get_driver_for_fd(int fd
)
327 int vendor_id
, chip_id
, i
, j
;
330 /* Allow an environment variable to force choosing a different driver
331 * binary. If that driver binary can't survive on this FD, that's the
332 * user's problem, but this allows vc4 simulator to run on an i965 host,
333 * and may be useful for some touch testing of i915 on an i965 host.
335 if (geteuid() == getuid()) {
336 driver
= getenv("MESA_LOADER_DRIVER_OVERRIDE");
338 return strdup(driver
);
341 if (!loader_get_pci_id_for_fd(fd
, &vendor_id
, &chip_id
)) {
344 /* fallback to drmGetVersion(): */
345 drmVersionPtr version
= drmGetVersion(fd
);
348 log_(_LOADER_WARNING
, "failed to get driver name for fd %d\n", fd
);
352 driver
= strndup(version
->name
, version
->name_len
);
353 log_(_LOADER_INFO
, "using driver %s for %d\n", driver
, fd
);
355 drmFreeVersion(version
);
361 for (i
= 0; driver_map
[i
].driver
; i
++) {
362 if (vendor_id
!= driver_map
[i
].vendor_id
)
365 if (driver_map
[i
].predicate
&& !driver_map
[i
].predicate(fd
))
368 if (driver_map
[i
].num_chips_ids
== -1) {
369 driver
= strdup(driver_map
[i
].driver
);
373 for (j
= 0; j
< driver_map
[i
].num_chips_ids
; j
++)
374 if (driver_map
[i
].chip_ids
[j
] == chip_id
) {
375 driver
= strdup(driver_map
[i
].driver
);
381 log_(driver
? _LOADER_DEBUG
: _LOADER_WARNING
,
382 "pci id for fd %d: %04x:%04x, driver %s\n",
383 fd
, vendor_id
, chip_id
, driver
);
388 loader_set_logger(void (*logger
)(int level
, const char *fmt
, ...))
393 /* XXX: Local definition to avoid pulling the heavyweight GL/gl.h and
394 * GL/internal/dri_interface.h
397 #ifndef __DRI_DRIVER_GET_EXTENSIONS
398 #define __DRI_DRIVER_GET_EXTENSIONS "__driDriverGetExtensions"
402 loader_get_extensions_name(const char *driver_name
)
406 if (asprintf(&name
, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS
, driver_name
) < 0)
409 const size_t len
= strlen(name
);
410 for (size_t i
= 0; i
< len
; i
++) {