xref: /aosp_15_r20/external/mesa3d/src/loader/loader.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2013 Rob Clark <[email protected]>
3*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2014-2016 Emil Velikov <[email protected]>
4*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2016 Intel Corporation
5*61046927SAndroid Build Coastguard Worker  *
6*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
7*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
8*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
9*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
11*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
12*61046927SAndroid Build Coastguard Worker  *
13*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
14*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
15*61046927SAndroid Build Coastguard Worker  * Software.
16*61046927SAndroid Build Coastguard Worker  *
17*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*61046927SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*61046927SAndroid Build Coastguard Worker  * SOFTWARE.
24*61046927SAndroid Build Coastguard Worker  *
25*61046927SAndroid Build Coastguard Worker  * Authors:
26*61046927SAndroid Build Coastguard Worker  *    Rob Clark <[email protected]>
27*61046927SAndroid Build Coastguard Worker  */
28*61046927SAndroid Build Coastguard Worker 
29*61046927SAndroid Build Coastguard Worker #include <dlfcn.h>
30*61046927SAndroid Build Coastguard Worker #include <errno.h>
31*61046927SAndroid Build Coastguard Worker #include <fcntl.h>
32*61046927SAndroid Build Coastguard Worker #include <sys/stat.h>
33*61046927SAndroid Build Coastguard Worker #include <stdarg.h>
34*61046927SAndroid Build Coastguard Worker #include <stdio.h>
35*61046927SAndroid Build Coastguard Worker #include <stdbool.h>
36*61046927SAndroid Build Coastguard Worker #include <string.h>
37*61046927SAndroid Build Coastguard Worker #include <unistd.h>
38*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
39*61046927SAndroid Build Coastguard Worker #include <limits.h>
40*61046927SAndroid Build Coastguard Worker #include <sys/param.h>
41*61046927SAndroid Build Coastguard Worker #ifdef MAJOR_IN_MKDEV
42*61046927SAndroid Build Coastguard Worker #include <sys/mkdev.h>
43*61046927SAndroid Build Coastguard Worker #endif
44*61046927SAndroid Build Coastguard Worker #ifdef MAJOR_IN_SYSMACROS
45*61046927SAndroid Build Coastguard Worker #include <sys/sysmacros.h>
46*61046927SAndroid Build Coastguard Worker #endif
47*61046927SAndroid Build Coastguard Worker #include <GL/gl.h>
48*61046927SAndroid Build Coastguard Worker #include "mesa_interface.h"
49*61046927SAndroid Build Coastguard Worker #include "loader.h"
50*61046927SAndroid Build Coastguard Worker #include "util/libdrm.h"
51*61046927SAndroid Build Coastguard Worker #include "util/os_file.h"
52*61046927SAndroid Build Coastguard Worker #include "util/os_misc.h"
53*61046927SAndroid Build Coastguard Worker #include "util/u_debug.h"
54*61046927SAndroid Build Coastguard Worker #include "git_sha1.h"
55*61046927SAndroid Build Coastguard Worker 
56*61046927SAndroid Build Coastguard Worker #include "drm-uapi/nouveau_drm.h"
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker #define MAX_DRM_DEVICES 64
59*61046927SAndroid Build Coastguard Worker 
60*61046927SAndroid Build Coastguard Worker #ifdef USE_DRICONF
61*61046927SAndroid Build Coastguard Worker #include "util/xmlconfig.h"
62*61046927SAndroid Build Coastguard Worker #include "util/driconf.h"
63*61046927SAndroid Build Coastguard Worker #endif
64*61046927SAndroid Build Coastguard Worker 
65*61046927SAndroid Build Coastguard Worker #include "util/macros.h"
66*61046927SAndroid Build Coastguard Worker 
67*61046927SAndroid Build Coastguard Worker #define __IS_LOADER
68*61046927SAndroid Build Coastguard Worker #include "pci_id_driver_map.h"
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker /* For systems like Hurd */
71*61046927SAndroid Build Coastguard Worker #ifndef PATH_MAX
72*61046927SAndroid Build Coastguard Worker #define PATH_MAX 4096
73*61046927SAndroid Build Coastguard Worker #endif
74*61046927SAndroid Build Coastguard Worker 
default_logger(int level,const char * fmt,...)75*61046927SAndroid Build Coastguard Worker static void default_logger(int level, const char *fmt, ...)
76*61046927SAndroid Build Coastguard Worker {
77*61046927SAndroid Build Coastguard Worker    if (level <= _LOADER_WARNING) {
78*61046927SAndroid Build Coastguard Worker       va_list args;
79*61046927SAndroid Build Coastguard Worker       va_start(args, fmt);
80*61046927SAndroid Build Coastguard Worker       vfprintf(stderr, fmt, args);
81*61046927SAndroid Build Coastguard Worker       va_end(args);
82*61046927SAndroid Build Coastguard Worker    }
83*61046927SAndroid Build Coastguard Worker }
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker static loader_logger *log_ = default_logger;
86*61046927SAndroid Build Coastguard Worker 
87*61046927SAndroid Build Coastguard Worker int
loader_open_device(const char * device_name)88*61046927SAndroid Build Coastguard Worker loader_open_device(const char *device_name)
89*61046927SAndroid Build Coastguard Worker {
90*61046927SAndroid Build Coastguard Worker    int fd;
91*61046927SAndroid Build Coastguard Worker #ifdef O_CLOEXEC
92*61046927SAndroid Build Coastguard Worker    fd = open(device_name, O_RDWR | O_CLOEXEC);
93*61046927SAndroid Build Coastguard Worker    if (fd == -1 && errno == EINVAL)
94*61046927SAndroid Build Coastguard Worker #endif
95*61046927SAndroid Build Coastguard Worker    {
96*61046927SAndroid Build Coastguard Worker       fd = open(device_name, O_RDWR);
97*61046927SAndroid Build Coastguard Worker       if (fd != -1)
98*61046927SAndroid Build Coastguard Worker          fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
99*61046927SAndroid Build Coastguard Worker    }
100*61046927SAndroid Build Coastguard Worker    if (fd == -1 && errno == EACCES) {
101*61046927SAndroid Build Coastguard Worker       log_(_LOADER_WARNING, "failed to open %s: %s\n",
102*61046927SAndroid Build Coastguard Worker            device_name, strerror(errno));
103*61046927SAndroid Build Coastguard Worker    }
104*61046927SAndroid Build Coastguard Worker    return fd;
105*61046927SAndroid Build Coastguard Worker }
106*61046927SAndroid Build Coastguard Worker 
107*61046927SAndroid Build Coastguard Worker char *
loader_get_kernel_driver_name(int fd)108*61046927SAndroid Build Coastguard Worker loader_get_kernel_driver_name(int fd)
109*61046927SAndroid Build Coastguard Worker {
110*61046927SAndroid Build Coastguard Worker    char *driver;
111*61046927SAndroid Build Coastguard Worker    drmVersionPtr version = drmGetVersion(fd);
112*61046927SAndroid Build Coastguard Worker 
113*61046927SAndroid Build Coastguard Worker    if (!version) {
114*61046927SAndroid Build Coastguard Worker       log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd);
115*61046927SAndroid Build Coastguard Worker       return NULL;
116*61046927SAndroid Build Coastguard Worker    }
117*61046927SAndroid Build Coastguard Worker 
118*61046927SAndroid Build Coastguard Worker    driver = strndup(version->name, version->name_len);
119*61046927SAndroid Build Coastguard Worker    log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, "using driver %s for %d\n",
120*61046927SAndroid Build Coastguard Worker         driver, fd);
121*61046927SAndroid Build Coastguard Worker 
122*61046927SAndroid Build Coastguard Worker    drmFreeVersion(version);
123*61046927SAndroid Build Coastguard Worker    return driver;
124*61046927SAndroid Build Coastguard Worker }
125*61046927SAndroid Build Coastguard Worker 
126*61046927SAndroid Build Coastguard Worker bool
iris_predicate(int fd,const char * driver)127*61046927SAndroid Build Coastguard Worker iris_predicate(int fd, const char *driver)
128*61046927SAndroid Build Coastguard Worker {
129*61046927SAndroid Build Coastguard Worker    char *kernel_driver = loader_get_kernel_driver_name(fd);
130*61046927SAndroid Build Coastguard Worker    bool ret = kernel_driver && (strcmp(kernel_driver, "i915") == 0 ||
131*61046927SAndroid Build Coastguard Worker                                 strcmp(kernel_driver, "xe") == 0);
132*61046927SAndroid Build Coastguard Worker 
133*61046927SAndroid Build Coastguard Worker    free(kernel_driver);
134*61046927SAndroid Build Coastguard Worker    return ret;
135*61046927SAndroid Build Coastguard Worker }
136*61046927SAndroid Build Coastguard Worker 
137*61046927SAndroid Build Coastguard Worker /* choose zink or nouveau GL */
138*61046927SAndroid Build Coastguard Worker bool
nouveau_zink_predicate(int fd,const char * driver)139*61046927SAndroid Build Coastguard Worker nouveau_zink_predicate(int fd, const char *driver)
140*61046927SAndroid Build Coastguard Worker {
141*61046927SAndroid Build Coastguard Worker #if !defined(HAVE_NVK) || !defined(HAVE_ZINK)
142*61046927SAndroid Build Coastguard Worker    if (!strcmp(driver, "zink"))
143*61046927SAndroid Build Coastguard Worker       return false;
144*61046927SAndroid Build Coastguard Worker    return true;
145*61046927SAndroid Build Coastguard Worker #else
146*61046927SAndroid Build Coastguard Worker 
147*61046927SAndroid Build Coastguard Worker    bool prefer_zink = false;
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker    /* enable this once zink is up to speed.
150*61046927SAndroid Build Coastguard Worker     * struct drm_nouveau_getparam r = { .param = NOUVEAU_GETPARAM_CHIPSET_ID };
151*61046927SAndroid Build Coastguard Worker     * int ret = drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r));
152*61046927SAndroid Build Coastguard Worker     * if (ret == 0 && (r.value & ~0xf) >= 0x160)
153*61046927SAndroid Build Coastguard Worker     *    prefer_zink = true;
154*61046927SAndroid Build Coastguard Worker     */
155*61046927SAndroid Build Coastguard Worker 
156*61046927SAndroid Build Coastguard Worker    prefer_zink = debug_get_bool_option("NOUVEAU_USE_ZINK", prefer_zink);
157*61046927SAndroid Build Coastguard Worker 
158*61046927SAndroid Build Coastguard Worker    if (prefer_zink && !strcmp(driver, "zink"))
159*61046927SAndroid Build Coastguard Worker       return true;
160*61046927SAndroid Build Coastguard Worker 
161*61046927SAndroid Build Coastguard Worker    if (!prefer_zink && !strcmp(driver, "nouveau"))
162*61046927SAndroid Build Coastguard Worker       return true;
163*61046927SAndroid Build Coastguard Worker    return false;
164*61046927SAndroid Build Coastguard Worker #endif
165*61046927SAndroid Build Coastguard Worker }
166*61046927SAndroid Build Coastguard Worker 
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker /**
169*61046927SAndroid Build Coastguard Worker  * Goes through all the platform devices whose driver is on the given list and
170*61046927SAndroid Build Coastguard Worker  * try to open their render node. It returns the fd of the first device that
171*61046927SAndroid Build Coastguard Worker  * it can open.
172*61046927SAndroid Build Coastguard Worker  */
173*61046927SAndroid Build Coastguard Worker int
loader_open_render_node_platform_device(const char * const drivers[],unsigned int n_drivers)174*61046927SAndroid Build Coastguard Worker loader_open_render_node_platform_device(const char * const drivers[],
175*61046927SAndroid Build Coastguard Worker                                         unsigned int n_drivers)
176*61046927SAndroid Build Coastguard Worker {
177*61046927SAndroid Build Coastguard Worker    drmDevicePtr devices[MAX_DRM_DEVICES], device;
178*61046927SAndroid Build Coastguard Worker    int num_devices, fd = -1;
179*61046927SAndroid Build Coastguard Worker    int i, j;
180*61046927SAndroid Build Coastguard Worker    bool found = false;
181*61046927SAndroid Build Coastguard Worker 
182*61046927SAndroid Build Coastguard Worker    num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
183*61046927SAndroid Build Coastguard Worker    if (num_devices <= 0)
184*61046927SAndroid Build Coastguard Worker       return -ENOENT;
185*61046927SAndroid Build Coastguard Worker 
186*61046927SAndroid Build Coastguard Worker    for (i = 0; i < num_devices; i++) {
187*61046927SAndroid Build Coastguard Worker       device = devices[i];
188*61046927SAndroid Build Coastguard Worker 
189*61046927SAndroid Build Coastguard Worker       if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
190*61046927SAndroid Build Coastguard Worker           (device->bustype == DRM_BUS_PLATFORM)) {
191*61046927SAndroid Build Coastguard Worker          drmVersionPtr version;
192*61046927SAndroid Build Coastguard Worker 
193*61046927SAndroid Build Coastguard Worker          fd = loader_open_device(device->nodes[DRM_NODE_RENDER]);
194*61046927SAndroid Build Coastguard Worker          if (fd < 0)
195*61046927SAndroid Build Coastguard Worker             continue;
196*61046927SAndroid Build Coastguard Worker 
197*61046927SAndroid Build Coastguard Worker          version = drmGetVersion(fd);
198*61046927SAndroid Build Coastguard Worker          if (!version) {
199*61046927SAndroid Build Coastguard Worker             close(fd);
200*61046927SAndroid Build Coastguard Worker             continue;
201*61046927SAndroid Build Coastguard Worker          }
202*61046927SAndroid Build Coastguard Worker 
203*61046927SAndroid Build Coastguard Worker          for (j = 0; j < n_drivers; j++) {
204*61046927SAndroid Build Coastguard Worker             if (strcmp(version->name, drivers[j]) == 0) {
205*61046927SAndroid Build Coastguard Worker                found = true;
206*61046927SAndroid Build Coastguard Worker                break;
207*61046927SAndroid Build Coastguard Worker             }
208*61046927SAndroid Build Coastguard Worker          }
209*61046927SAndroid Build Coastguard Worker          if (!found) {
210*61046927SAndroid Build Coastguard Worker             drmFreeVersion(version);
211*61046927SAndroid Build Coastguard Worker             close(fd);
212*61046927SAndroid Build Coastguard Worker             continue;
213*61046927SAndroid Build Coastguard Worker          }
214*61046927SAndroid Build Coastguard Worker 
215*61046927SAndroid Build Coastguard Worker          drmFreeVersion(version);
216*61046927SAndroid Build Coastguard Worker          break;
217*61046927SAndroid Build Coastguard Worker       }
218*61046927SAndroid Build Coastguard Worker    }
219*61046927SAndroid Build Coastguard Worker    drmFreeDevices(devices, num_devices);
220*61046927SAndroid Build Coastguard Worker 
221*61046927SAndroid Build Coastguard Worker    if (i == num_devices)
222*61046927SAndroid Build Coastguard Worker       return -ENOENT;
223*61046927SAndroid Build Coastguard Worker 
224*61046927SAndroid Build Coastguard Worker    return fd;
225*61046927SAndroid Build Coastguard Worker }
226*61046927SAndroid Build Coastguard Worker 
227*61046927SAndroid Build Coastguard Worker bool
loader_is_device_render_capable(int fd)228*61046927SAndroid Build Coastguard Worker loader_is_device_render_capable(int fd)
229*61046927SAndroid Build Coastguard Worker {
230*61046927SAndroid Build Coastguard Worker    drmDevicePtr dev_ptr;
231*61046927SAndroid Build Coastguard Worker    bool ret;
232*61046927SAndroid Build Coastguard Worker 
233*61046927SAndroid Build Coastguard Worker    if (drmGetDevice2(fd, 0, &dev_ptr) != 0)
234*61046927SAndroid Build Coastguard Worker       return false;
235*61046927SAndroid Build Coastguard Worker 
236*61046927SAndroid Build Coastguard Worker    ret = (dev_ptr->available_nodes & (1 << DRM_NODE_RENDER));
237*61046927SAndroid Build Coastguard Worker 
238*61046927SAndroid Build Coastguard Worker    drmFreeDevice(&dev_ptr);
239*61046927SAndroid Build Coastguard Worker 
240*61046927SAndroid Build Coastguard Worker    return ret;
241*61046927SAndroid Build Coastguard Worker }
242*61046927SAndroid Build Coastguard Worker 
243*61046927SAndroid Build Coastguard Worker char *
loader_get_render_node(dev_t device)244*61046927SAndroid Build Coastguard Worker loader_get_render_node(dev_t device)
245*61046927SAndroid Build Coastguard Worker {
246*61046927SAndroid Build Coastguard Worker    char *render_node = NULL;
247*61046927SAndroid Build Coastguard Worker    drmDevicePtr dev_ptr;
248*61046927SAndroid Build Coastguard Worker 
249*61046927SAndroid Build Coastguard Worker    if (drmGetDeviceFromDevId(device, 0, &dev_ptr) < 0)
250*61046927SAndroid Build Coastguard Worker       return NULL;
251*61046927SAndroid Build Coastguard Worker 
252*61046927SAndroid Build Coastguard Worker    if (dev_ptr->available_nodes & (1 << DRM_NODE_RENDER)) {
253*61046927SAndroid Build Coastguard Worker       render_node = strdup(dev_ptr->nodes[DRM_NODE_RENDER]);
254*61046927SAndroid Build Coastguard Worker       if (!render_node)
255*61046927SAndroid Build Coastguard Worker          log_(_LOADER_DEBUG, "MESA-LOADER: failed to allocate memory for render node\n");
256*61046927SAndroid Build Coastguard Worker    }
257*61046927SAndroid Build Coastguard Worker 
258*61046927SAndroid Build Coastguard Worker    drmFreeDevice(&dev_ptr);
259*61046927SAndroid Build Coastguard Worker 
260*61046927SAndroid Build Coastguard Worker    return render_node;
261*61046927SAndroid Build Coastguard Worker }
262*61046927SAndroid Build Coastguard Worker 
263*61046927SAndroid Build Coastguard Worker #ifdef USE_DRICONF
264*61046927SAndroid Build Coastguard Worker static const driOptionDescription __driConfigOptionsLoader[] = {
265*61046927SAndroid Build Coastguard Worker     DRI_CONF_SECTION_INITIALIZATION
266*61046927SAndroid Build Coastguard Worker         DRI_CONF_DEVICE_ID_PATH_TAG()
267*61046927SAndroid Build Coastguard Worker         DRI_CONF_DRI_DRIVER()
268*61046927SAndroid Build Coastguard Worker     DRI_CONF_SECTION_END
269*61046927SAndroid Build Coastguard Worker };
270*61046927SAndroid Build Coastguard Worker 
loader_get_dri_config_driver(int fd)271*61046927SAndroid Build Coastguard Worker static char *loader_get_dri_config_driver(int fd)
272*61046927SAndroid Build Coastguard Worker {
273*61046927SAndroid Build Coastguard Worker    driOptionCache defaultInitOptions;
274*61046927SAndroid Build Coastguard Worker    driOptionCache userInitOptions;
275*61046927SAndroid Build Coastguard Worker    char *dri_driver = NULL;
276*61046927SAndroid Build Coastguard Worker    char *kernel_driver = loader_get_kernel_driver_name(fd);
277*61046927SAndroid Build Coastguard Worker 
278*61046927SAndroid Build Coastguard Worker    driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader,
279*61046927SAndroid Build Coastguard Worker                       ARRAY_SIZE(__driConfigOptionsLoader));
280*61046927SAndroid Build Coastguard Worker    driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
281*61046927SAndroid Build Coastguard Worker                        "loader", kernel_driver, NULL, NULL, 0, NULL, 0);
282*61046927SAndroid Build Coastguard Worker    if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) {
283*61046927SAndroid Build Coastguard Worker       char *opt = driQueryOptionstr(&userInitOptions, "dri_driver");
284*61046927SAndroid Build Coastguard Worker       /* not an empty string */
285*61046927SAndroid Build Coastguard Worker       if (*opt)
286*61046927SAndroid Build Coastguard Worker          dri_driver = strdup(opt);
287*61046927SAndroid Build Coastguard Worker    }
288*61046927SAndroid Build Coastguard Worker    driDestroyOptionCache(&userInitOptions);
289*61046927SAndroid Build Coastguard Worker    driDestroyOptionInfo(&defaultInitOptions);
290*61046927SAndroid Build Coastguard Worker 
291*61046927SAndroid Build Coastguard Worker    free(kernel_driver);
292*61046927SAndroid Build Coastguard Worker    return dri_driver;
293*61046927SAndroid Build Coastguard Worker }
294*61046927SAndroid Build Coastguard Worker 
loader_get_dri_config_device_id(void)295*61046927SAndroid Build Coastguard Worker static char *loader_get_dri_config_device_id(void)
296*61046927SAndroid Build Coastguard Worker {
297*61046927SAndroid Build Coastguard Worker    driOptionCache defaultInitOptions;
298*61046927SAndroid Build Coastguard Worker    driOptionCache userInitOptions;
299*61046927SAndroid Build Coastguard Worker    char *prime = NULL;
300*61046927SAndroid Build Coastguard Worker 
301*61046927SAndroid Build Coastguard Worker    driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader,
302*61046927SAndroid Build Coastguard Worker                       ARRAY_SIZE(__driConfigOptionsLoader));
303*61046927SAndroid Build Coastguard Worker    driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
304*61046927SAndroid Build Coastguard Worker                        "loader", NULL, NULL, NULL, 0, NULL, 0);
305*61046927SAndroid Build Coastguard Worker    if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) {
306*61046927SAndroid Build Coastguard Worker       char *opt = driQueryOptionstr(&userInitOptions, "device_id");
307*61046927SAndroid Build Coastguard Worker       if (*opt)
308*61046927SAndroid Build Coastguard Worker          prime = strdup(opt);
309*61046927SAndroid Build Coastguard Worker    }
310*61046927SAndroid Build Coastguard Worker    driDestroyOptionCache(&userInitOptions);
311*61046927SAndroid Build Coastguard Worker    driDestroyOptionInfo(&defaultInitOptions);
312*61046927SAndroid Build Coastguard Worker 
313*61046927SAndroid Build Coastguard Worker    return prime;
314*61046927SAndroid Build Coastguard Worker }
315*61046927SAndroid Build Coastguard Worker #endif
316*61046927SAndroid Build Coastguard Worker 
drm_construct_id_path_tag(drmDevicePtr device)317*61046927SAndroid Build Coastguard Worker static char *drm_construct_id_path_tag(drmDevicePtr device)
318*61046927SAndroid Build Coastguard Worker {
319*61046927SAndroid Build Coastguard Worker    char *tag = NULL;
320*61046927SAndroid Build Coastguard Worker 
321*61046927SAndroid Build Coastguard Worker    if (device->bustype == DRM_BUS_PCI) {
322*61046927SAndroid Build Coastguard Worker       if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u",
323*61046927SAndroid Build Coastguard Worker                    device->businfo.pci->domain,
324*61046927SAndroid Build Coastguard Worker                    device->businfo.pci->bus,
325*61046927SAndroid Build Coastguard Worker                    device->businfo.pci->dev,
326*61046927SAndroid Build Coastguard Worker                    device->businfo.pci->func) < 0) {
327*61046927SAndroid Build Coastguard Worker          return NULL;
328*61046927SAndroid Build Coastguard Worker       }
329*61046927SAndroid Build Coastguard Worker    } else if (device->bustype == DRM_BUS_PLATFORM ||
330*61046927SAndroid Build Coastguard Worker               device->bustype == DRM_BUS_HOST1X) {
331*61046927SAndroid Build Coastguard Worker       char *fullname, *name, *address;
332*61046927SAndroid Build Coastguard Worker 
333*61046927SAndroid Build Coastguard Worker       if (device->bustype == DRM_BUS_PLATFORM)
334*61046927SAndroid Build Coastguard Worker          fullname = device->businfo.platform->fullname;
335*61046927SAndroid Build Coastguard Worker       else
336*61046927SAndroid Build Coastguard Worker          fullname = device->businfo.host1x->fullname;
337*61046927SAndroid Build Coastguard Worker 
338*61046927SAndroid Build Coastguard Worker       name = strrchr(fullname, '/');
339*61046927SAndroid Build Coastguard Worker       if (!name)
340*61046927SAndroid Build Coastguard Worker          name = strdup(fullname);
341*61046927SAndroid Build Coastguard Worker       else
342*61046927SAndroid Build Coastguard Worker          name = strdup(name + 1);
343*61046927SAndroid Build Coastguard Worker 
344*61046927SAndroid Build Coastguard Worker       address = strchr(name, '@');
345*61046927SAndroid Build Coastguard Worker       if (address) {
346*61046927SAndroid Build Coastguard Worker          *address++ = '\0';
347*61046927SAndroid Build Coastguard Worker 
348*61046927SAndroid Build Coastguard Worker          if (asprintf(&tag, "platform-%s_%s", address, name) < 0)
349*61046927SAndroid Build Coastguard Worker             tag = NULL;
350*61046927SAndroid Build Coastguard Worker       } else {
351*61046927SAndroid Build Coastguard Worker          if (asprintf(&tag, "platform-%s", name) < 0)
352*61046927SAndroid Build Coastguard Worker             tag = NULL;
353*61046927SAndroid Build Coastguard Worker       }
354*61046927SAndroid Build Coastguard Worker 
355*61046927SAndroid Build Coastguard Worker       free(name);
356*61046927SAndroid Build Coastguard Worker    }
357*61046927SAndroid Build Coastguard Worker    return tag;
358*61046927SAndroid Build Coastguard Worker }
359*61046927SAndroid Build Coastguard Worker 
drm_device_matches_tag(drmDevicePtr device,const char * prime_tag)360*61046927SAndroid Build Coastguard Worker static bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag)
361*61046927SAndroid Build Coastguard Worker {
362*61046927SAndroid Build Coastguard Worker    char *tag = drm_construct_id_path_tag(device);
363*61046927SAndroid Build Coastguard Worker    int ret;
364*61046927SAndroid Build Coastguard Worker 
365*61046927SAndroid Build Coastguard Worker    if (tag == NULL)
366*61046927SAndroid Build Coastguard Worker       return false;
367*61046927SAndroid Build Coastguard Worker 
368*61046927SAndroid Build Coastguard Worker    ret = strcmp(tag, prime_tag);
369*61046927SAndroid Build Coastguard Worker 
370*61046927SAndroid Build Coastguard Worker    free(tag);
371*61046927SAndroid Build Coastguard Worker    return ret == 0;
372*61046927SAndroid Build Coastguard Worker }
373*61046927SAndroid Build Coastguard Worker 
drm_get_id_path_tag_for_fd(int fd)374*61046927SAndroid Build Coastguard Worker static char *drm_get_id_path_tag_for_fd(int fd)
375*61046927SAndroid Build Coastguard Worker {
376*61046927SAndroid Build Coastguard Worker    drmDevicePtr device;
377*61046927SAndroid Build Coastguard Worker    char *tag;
378*61046927SAndroid Build Coastguard Worker 
379*61046927SAndroid Build Coastguard Worker    if (drmGetDevice2(fd, 0, &device) != 0)
380*61046927SAndroid Build Coastguard Worker        return NULL;
381*61046927SAndroid Build Coastguard Worker 
382*61046927SAndroid Build Coastguard Worker    tag = drm_construct_id_path_tag(device);
383*61046927SAndroid Build Coastguard Worker    drmFreeDevice(&device);
384*61046927SAndroid Build Coastguard Worker    return tag;
385*61046927SAndroid Build Coastguard Worker }
386*61046927SAndroid Build Coastguard Worker 
loader_get_user_preferred_fd(int * fd_render_gpu,int * original_fd)387*61046927SAndroid Build Coastguard Worker bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
388*61046927SAndroid Build Coastguard Worker {
389*61046927SAndroid Build Coastguard Worker    const char *dri_prime = getenv("DRI_PRIME");
390*61046927SAndroid Build Coastguard Worker    bool debug = debug_get_bool_option("DRI_PRIME_DEBUG", false);
391*61046927SAndroid Build Coastguard Worker    char *default_tag = NULL;
392*61046927SAndroid Build Coastguard Worker    drmDevicePtr devices[MAX_DRM_DEVICES];
393*61046927SAndroid Build Coastguard Worker    int i, num_devices, fd = -1;
394*61046927SAndroid Build Coastguard Worker    struct {
395*61046927SAndroid Build Coastguard Worker       enum {
396*61046927SAndroid Build Coastguard Worker          PRIME_IS_INTEGER,
397*61046927SAndroid Build Coastguard Worker          PRIME_IS_VID_DID,
398*61046927SAndroid Build Coastguard Worker          PRIME_IS_PCI_TAG
399*61046927SAndroid Build Coastguard Worker       } semantics;
400*61046927SAndroid Build Coastguard Worker       union {
401*61046927SAndroid Build Coastguard Worker          int as_integer;
402*61046927SAndroid Build Coastguard Worker          struct {
403*61046927SAndroid Build Coastguard Worker             uint16_t v, d;
404*61046927SAndroid Build Coastguard Worker          } as_vendor_device_ids;
405*61046927SAndroid Build Coastguard Worker       } v;
406*61046927SAndroid Build Coastguard Worker       char *str;
407*61046927SAndroid Build Coastguard Worker    } prime = {};
408*61046927SAndroid Build Coastguard Worker    prime.str = NULL;
409*61046927SAndroid Build Coastguard Worker 
410*61046927SAndroid Build Coastguard Worker    if (dri_prime)
411*61046927SAndroid Build Coastguard Worker       prime.str = strdup(dri_prime);
412*61046927SAndroid Build Coastguard Worker #ifdef USE_DRICONF
413*61046927SAndroid Build Coastguard Worker    else
414*61046927SAndroid Build Coastguard Worker       prime.str = loader_get_dri_config_device_id();
415*61046927SAndroid Build Coastguard Worker #endif
416*61046927SAndroid Build Coastguard Worker 
417*61046927SAndroid Build Coastguard Worker    if (prime.str == NULL) {
418*61046927SAndroid Build Coastguard Worker       goto no_prime_gpu_offloading;
419*61046927SAndroid Build Coastguard Worker    } else {
420*61046927SAndroid Build Coastguard Worker       uint16_t vendor_id, device_id;
421*61046927SAndroid Build Coastguard Worker       if (sscanf(prime.str, "%hx:%hx", &vendor_id, &device_id) == 2) {
422*61046927SAndroid Build Coastguard Worker          prime.semantics = PRIME_IS_VID_DID;
423*61046927SAndroid Build Coastguard Worker          prime.v.as_vendor_device_ids.v = vendor_id;
424*61046927SAndroid Build Coastguard Worker          prime.v.as_vendor_device_ids.d = device_id;
425*61046927SAndroid Build Coastguard Worker       } else {
426*61046927SAndroid Build Coastguard Worker          int i = atoi(prime.str);
427*61046927SAndroid Build Coastguard Worker          if (i < 0 || strcmp(prime.str, "0") == 0) {
428*61046927SAndroid Build Coastguard Worker             printf("Invalid value (%d) for DRI_PRIME. Should be > 0\n", i);
429*61046927SAndroid Build Coastguard Worker             goto err;
430*61046927SAndroid Build Coastguard Worker          } else if (i == 0) {
431*61046927SAndroid Build Coastguard Worker             prime.semantics = PRIME_IS_PCI_TAG;
432*61046927SAndroid Build Coastguard Worker          } else {
433*61046927SAndroid Build Coastguard Worker             prime.semantics = PRIME_IS_INTEGER;
434*61046927SAndroid Build Coastguard Worker             prime.v.as_integer = i;
435*61046927SAndroid Build Coastguard Worker          }
436*61046927SAndroid Build Coastguard Worker       }
437*61046927SAndroid Build Coastguard Worker    }
438*61046927SAndroid Build Coastguard Worker 
439*61046927SAndroid Build Coastguard Worker    default_tag = drm_get_id_path_tag_for_fd(*fd_render_gpu);
440*61046927SAndroid Build Coastguard Worker    if (default_tag == NULL)
441*61046927SAndroid Build Coastguard Worker       goto err;
442*61046927SAndroid Build Coastguard Worker 
443*61046927SAndroid Build Coastguard Worker    num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
444*61046927SAndroid Build Coastguard Worker    if (num_devices <= 0)
445*61046927SAndroid Build Coastguard Worker       goto err;
446*61046927SAndroid Build Coastguard Worker 
447*61046927SAndroid Build Coastguard Worker    if (debug) {
448*61046927SAndroid Build Coastguard Worker       log_(_LOADER_WARNING, "DRI_PRIME: %d devices\n", num_devices);
449*61046927SAndroid Build Coastguard Worker       for (i = 0; i < num_devices; i++) {
450*61046927SAndroid Build Coastguard Worker          log_(_LOADER_WARNING, "  %d:", i);
451*61046927SAndroid Build Coastguard Worker          if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER)) {
452*61046927SAndroid Build Coastguard Worker             log_(_LOADER_WARNING, "not a render node -> not usable\n");
453*61046927SAndroid Build Coastguard Worker             continue;
454*61046927SAndroid Build Coastguard Worker          }
455*61046927SAndroid Build Coastguard Worker          char *tag = drm_construct_id_path_tag(devices[i]);
456*61046927SAndroid Build Coastguard Worker          if (tag) {
457*61046927SAndroid Build Coastguard Worker             log_(_LOADER_WARNING, " %s", tag);
458*61046927SAndroid Build Coastguard Worker             free(tag);
459*61046927SAndroid Build Coastguard Worker          }
460*61046927SAndroid Build Coastguard Worker          if (devices[i]->bustype == DRM_BUS_PCI) {
461*61046927SAndroid Build Coastguard Worker             log_(_LOADER_WARNING, " %4x:%4x",
462*61046927SAndroid Build Coastguard Worker                devices[i]->deviceinfo.pci->vendor_id,
463*61046927SAndroid Build Coastguard Worker                devices[i]->deviceinfo.pci->device_id);
464*61046927SAndroid Build Coastguard Worker          }
465*61046927SAndroid Build Coastguard Worker          log_(_LOADER_WARNING, " %s", devices[i]->nodes[DRM_NODE_RENDER]);
466*61046927SAndroid Build Coastguard Worker 
467*61046927SAndroid Build Coastguard Worker          if (drm_device_matches_tag(devices[i], default_tag)) {
468*61046927SAndroid Build Coastguard Worker             log_(_LOADER_WARNING, " [default]");
469*61046927SAndroid Build Coastguard Worker          }
470*61046927SAndroid Build Coastguard Worker          log_(_LOADER_WARNING, "\n");
471*61046927SAndroid Build Coastguard Worker       }
472*61046927SAndroid Build Coastguard Worker    }
473*61046927SAndroid Build Coastguard Worker 
474*61046927SAndroid Build Coastguard Worker    if (prime.semantics == PRIME_IS_INTEGER &&
475*61046927SAndroid Build Coastguard Worker        prime.v.as_integer >= num_devices) {
476*61046927SAndroid Build Coastguard Worker       printf("Inconsistent value (%d) for DRI_PRIME. Should be < %d "
477*61046927SAndroid Build Coastguard Worker              "(GPU devices count). Using: %d\n",
478*61046927SAndroid Build Coastguard Worker              prime.v.as_integer, num_devices, num_devices - 1);
479*61046927SAndroid Build Coastguard Worker       prime.v.as_integer = num_devices - 1;
480*61046927SAndroid Build Coastguard Worker    }
481*61046927SAndroid Build Coastguard Worker 
482*61046927SAndroid Build Coastguard Worker    for (i = 0; i < num_devices; i++) {
483*61046927SAndroid Build Coastguard Worker       if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
484*61046927SAndroid Build Coastguard Worker          continue;
485*61046927SAndroid Build Coastguard Worker 
486*61046927SAndroid Build Coastguard Worker       log_(debug ? _LOADER_WARNING : _LOADER_INFO, "DRI_PRIME: device %d ", i);
487*61046927SAndroid Build Coastguard Worker 
488*61046927SAndroid Build Coastguard Worker       /* three formats of DRI_PRIME are supported:
489*61046927SAndroid Build Coastguard Worker        * "N": a >= 1 integer value. Select the Nth GPU, skipping the
490*61046927SAndroid Build Coastguard Worker        *      default one.
491*61046927SAndroid Build Coastguard Worker        * id_path_tag: (for example "pci-0000_02_00_0") choose the card
492*61046927SAndroid Build Coastguard Worker        * with this id_path_tag.
493*61046927SAndroid Build Coastguard Worker        * vendor_id:device_id
494*61046927SAndroid Build Coastguard Worker        */
495*61046927SAndroid Build Coastguard Worker       switch (prime.semantics) {
496*61046927SAndroid Build Coastguard Worker          case PRIME_IS_INTEGER: {
497*61046927SAndroid Build Coastguard Worker             /* Skip the default device */
498*61046927SAndroid Build Coastguard Worker             if (drm_device_matches_tag(devices[i], default_tag)) {
499*61046927SAndroid Build Coastguard Worker                log_(debug ? _LOADER_WARNING : _LOADER_INFO,
500*61046927SAndroid Build Coastguard Worker                     "skipped (default device)\n");
501*61046927SAndroid Build Coastguard Worker                continue;
502*61046927SAndroid Build Coastguard Worker             }
503*61046927SAndroid Build Coastguard Worker             prime.v.as_integer--;
504*61046927SAndroid Build Coastguard Worker 
505*61046927SAndroid Build Coastguard Worker             /* Skip more GPUs? */
506*61046927SAndroid Build Coastguard Worker             if (prime.v.as_integer) {
507*61046927SAndroid Build Coastguard Worker                log_(debug ? _LOADER_WARNING : _LOADER_INFO,
508*61046927SAndroid Build Coastguard Worker                     "skipped (%d more to skip)\n", prime.v.as_integer - 1);
509*61046927SAndroid Build Coastguard Worker                continue;
510*61046927SAndroid Build Coastguard Worker             }
511*61046927SAndroid Build Coastguard Worker             log_(debug ? _LOADER_WARNING : _LOADER_INFO, " -> ");
512*61046927SAndroid Build Coastguard Worker             break;
513*61046927SAndroid Build Coastguard Worker          }
514*61046927SAndroid Build Coastguard Worker          case PRIME_IS_VID_DID: {
515*61046927SAndroid Build Coastguard Worker             if (devices[i]->bustype == DRM_BUS_PCI &&
516*61046927SAndroid Build Coastguard Worker                 devices[i]->deviceinfo.pci->vendor_id == prime.v.as_vendor_device_ids.v &&
517*61046927SAndroid Build Coastguard Worker                 devices[i]->deviceinfo.pci->device_id == prime.v.as_vendor_device_ids.d) {
518*61046927SAndroid Build Coastguard Worker                /* Update prime for the "different_device"
519*61046927SAndroid Build Coastguard Worker                 * determination below. */
520*61046927SAndroid Build Coastguard Worker                free(prime.str);
521*61046927SAndroid Build Coastguard Worker                prime.str = drm_construct_id_path_tag(devices[i]);
522*61046927SAndroid Build Coastguard Worker                log_(debug ? _LOADER_WARNING : _LOADER_INFO,
523*61046927SAndroid Build Coastguard Worker                     " - vid:did match -> ");
524*61046927SAndroid Build Coastguard Worker                break;
525*61046927SAndroid Build Coastguard Worker             } else {
526*61046927SAndroid Build Coastguard Worker                log_(debug ? _LOADER_WARNING : _LOADER_INFO,
527*61046927SAndroid Build Coastguard Worker                     "skipped (vid:did didn't match)\n");
528*61046927SAndroid Build Coastguard Worker             }
529*61046927SAndroid Build Coastguard Worker             continue;
530*61046927SAndroid Build Coastguard Worker          }
531*61046927SAndroid Build Coastguard Worker          case PRIME_IS_PCI_TAG: {
532*61046927SAndroid Build Coastguard Worker             if (!drm_device_matches_tag(devices[i], prime.str)) {
533*61046927SAndroid Build Coastguard Worker                log_(debug ? _LOADER_WARNING : _LOADER_INFO,
534*61046927SAndroid Build Coastguard Worker                     "skipped (pci id tag didn't match)\n");
535*61046927SAndroid Build Coastguard Worker                continue;
536*61046927SAndroid Build Coastguard Worker             }
537*61046927SAndroid Build Coastguard Worker             log_(debug ? _LOADER_WARNING : _LOADER_INFO, " - pci tag match -> ");
538*61046927SAndroid Build Coastguard Worker             break;
539*61046927SAndroid Build Coastguard Worker          }
540*61046927SAndroid Build Coastguard Worker       }
541*61046927SAndroid Build Coastguard Worker 
542*61046927SAndroid Build Coastguard Worker       log_(debug ? _LOADER_WARNING : _LOADER_INFO,
543*61046927SAndroid Build Coastguard Worker            "selected (%s)\n", devices[i]->nodes[DRM_NODE_RENDER]);
544*61046927SAndroid Build Coastguard Worker       fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]);
545*61046927SAndroid Build Coastguard Worker       break;
546*61046927SAndroid Build Coastguard Worker    }
547*61046927SAndroid Build Coastguard Worker    drmFreeDevices(devices, num_devices);
548*61046927SAndroid Build Coastguard Worker 
549*61046927SAndroid Build Coastguard Worker    if (i == num_devices)
550*61046927SAndroid Build Coastguard Worker       goto err;
551*61046927SAndroid Build Coastguard Worker 
552*61046927SAndroid Build Coastguard Worker    if (fd < 0) {
553*61046927SAndroid Build Coastguard Worker       log_(debug ? _LOADER_WARNING : _LOADER_INFO,
554*61046927SAndroid Build Coastguard Worker            "DRI_PRIME: failed to open '%s'\n",
555*61046927SAndroid Build Coastguard Worker            devices[i]->nodes[DRM_NODE_RENDER]);
556*61046927SAndroid Build Coastguard Worker 
557*61046927SAndroid Build Coastguard Worker       goto err;
558*61046927SAndroid Build Coastguard Worker    }
559*61046927SAndroid Build Coastguard Worker 
560*61046927SAndroid Build Coastguard Worker    bool is_render_and_display_gpu_diff = !!strcmp(default_tag, prime.str);
561*61046927SAndroid Build Coastguard Worker    if (original_fd) {
562*61046927SAndroid Build Coastguard Worker       if (is_render_and_display_gpu_diff) {
563*61046927SAndroid Build Coastguard Worker          *original_fd = *fd_render_gpu;
564*61046927SAndroid Build Coastguard Worker          *fd_render_gpu = fd;
565*61046927SAndroid Build Coastguard Worker       } else {
566*61046927SAndroid Build Coastguard Worker          *original_fd = *fd_render_gpu;
567*61046927SAndroid Build Coastguard Worker          close(fd);
568*61046927SAndroid Build Coastguard Worker       }
569*61046927SAndroid Build Coastguard Worker    } else {
570*61046927SAndroid Build Coastguard Worker       close(*fd_render_gpu);
571*61046927SAndroid Build Coastguard Worker       *fd_render_gpu = fd;
572*61046927SAndroid Build Coastguard Worker    }
573*61046927SAndroid Build Coastguard Worker 
574*61046927SAndroid Build Coastguard Worker    free(default_tag);
575*61046927SAndroid Build Coastguard Worker    free(prime.str);
576*61046927SAndroid Build Coastguard Worker    return is_render_and_display_gpu_diff;
577*61046927SAndroid Build Coastguard Worker  err:
578*61046927SAndroid Build Coastguard Worker    log_(debug ? _LOADER_WARNING : _LOADER_INFO,
579*61046927SAndroid Build Coastguard Worker         "DRI_PRIME: error. Using the default GPU\n");
580*61046927SAndroid Build Coastguard Worker    free(default_tag);
581*61046927SAndroid Build Coastguard Worker    free(prime.str);
582*61046927SAndroid Build Coastguard Worker  no_prime_gpu_offloading:
583*61046927SAndroid Build Coastguard Worker    if (original_fd)
584*61046927SAndroid Build Coastguard Worker       *original_fd = *fd_render_gpu;
585*61046927SAndroid Build Coastguard Worker    return false;
586*61046927SAndroid Build Coastguard Worker }
587*61046927SAndroid Build Coastguard Worker 
588*61046927SAndroid Build Coastguard Worker static bool
drm_get_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)589*61046927SAndroid Build Coastguard Worker drm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
590*61046927SAndroid Build Coastguard Worker {
591*61046927SAndroid Build Coastguard Worker    drmDevicePtr device;
592*61046927SAndroid Build Coastguard Worker 
593*61046927SAndroid Build Coastguard Worker    if (drmGetDevice2(fd, 0, &device) != 0) {
594*61046927SAndroid Build Coastguard Worker       log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n");
595*61046927SAndroid Build Coastguard Worker       return false;
596*61046927SAndroid Build Coastguard Worker    }
597*61046927SAndroid Build Coastguard Worker 
598*61046927SAndroid Build Coastguard Worker    if (device->bustype != DRM_BUS_PCI) {
599*61046927SAndroid Build Coastguard Worker       drmFreeDevice(&device);
600*61046927SAndroid Build Coastguard Worker       log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n");
601*61046927SAndroid Build Coastguard Worker       return false;
602*61046927SAndroid Build Coastguard Worker    }
603*61046927SAndroid Build Coastguard Worker 
604*61046927SAndroid Build Coastguard Worker    *vendor_id = device->deviceinfo.pci->vendor_id;
605*61046927SAndroid Build Coastguard Worker    *chip_id = device->deviceinfo.pci->device_id;
606*61046927SAndroid Build Coastguard Worker    drmFreeDevice(&device);
607*61046927SAndroid Build Coastguard Worker    return true;
608*61046927SAndroid Build Coastguard Worker }
609*61046927SAndroid Build Coastguard Worker 
610*61046927SAndroid Build Coastguard Worker #ifdef __linux__
loader_get_linux_pci_field(int maj,int min,const char * field)611*61046927SAndroid Build Coastguard Worker static int loader_get_linux_pci_field(int maj, int min, const char *field)
612*61046927SAndroid Build Coastguard Worker {
613*61046927SAndroid Build Coastguard Worker    char path[PATH_MAX + 1];
614*61046927SAndroid Build Coastguard Worker    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/%s", maj, min, field);
615*61046927SAndroid Build Coastguard Worker 
616*61046927SAndroid Build Coastguard Worker    char *field_str = os_read_file(path, NULL);
617*61046927SAndroid Build Coastguard Worker    if (!field_str) {
618*61046927SAndroid Build Coastguard Worker       /* Probably non-PCI device. */
619*61046927SAndroid Build Coastguard Worker       return 0;
620*61046927SAndroid Build Coastguard Worker    }
621*61046927SAndroid Build Coastguard Worker 
622*61046927SAndroid Build Coastguard Worker    int value = (int)strtoll(field_str, NULL, 16);
623*61046927SAndroid Build Coastguard Worker    free(field_str);
624*61046927SAndroid Build Coastguard Worker 
625*61046927SAndroid Build Coastguard Worker    return value;
626*61046927SAndroid Build Coastguard Worker }
627*61046927SAndroid Build Coastguard Worker 
628*61046927SAndroid Build Coastguard Worker static bool
loader_get_linux_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)629*61046927SAndroid Build Coastguard Worker loader_get_linux_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
630*61046927SAndroid Build Coastguard Worker {
631*61046927SAndroid Build Coastguard Worker    struct stat sbuf;
632*61046927SAndroid Build Coastguard Worker    if (fstat(fd, &sbuf) != 0) {
633*61046927SAndroid Build Coastguard Worker       log_(_LOADER_DEBUG, "MESA-LOADER: failed to fstat fd\n");
634*61046927SAndroid Build Coastguard Worker       return false;
635*61046927SAndroid Build Coastguard Worker    }
636*61046927SAndroid Build Coastguard Worker 
637*61046927SAndroid Build Coastguard Worker    int maj = major(sbuf.st_rdev);
638*61046927SAndroid Build Coastguard Worker    int min = minor(sbuf.st_rdev);
639*61046927SAndroid Build Coastguard Worker 
640*61046927SAndroid Build Coastguard Worker    *vendor_id = loader_get_linux_pci_field(maj, min, "vendor");
641*61046927SAndroid Build Coastguard Worker    *chip_id = loader_get_linux_pci_field(maj, min, "device");
642*61046927SAndroid Build Coastguard Worker 
643*61046927SAndroid Build Coastguard Worker    return *vendor_id && *chip_id;
644*61046927SAndroid Build Coastguard Worker }
645*61046927SAndroid Build Coastguard Worker #endif /* __linux__ */
646*61046927SAndroid Build Coastguard Worker 
647*61046927SAndroid Build Coastguard Worker bool
loader_get_pci_id_for_fd(int fd,int * vendor_id,int * chip_id)648*61046927SAndroid Build Coastguard Worker loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
649*61046927SAndroid Build Coastguard Worker {
650*61046927SAndroid Build Coastguard Worker #ifdef __linux__
651*61046927SAndroid Build Coastguard Worker    /* Implementation without causing full enumeration of DRM devices. */
652*61046927SAndroid Build Coastguard Worker    if (loader_get_linux_pci_id_for_fd(fd, vendor_id, chip_id))
653*61046927SAndroid Build Coastguard Worker       return true;
654*61046927SAndroid Build Coastguard Worker #endif
655*61046927SAndroid Build Coastguard Worker 
656*61046927SAndroid Build Coastguard Worker    return drm_get_pci_id_for_fd(fd, vendor_id, chip_id);
657*61046927SAndroid Build Coastguard Worker }
658*61046927SAndroid Build Coastguard Worker 
659*61046927SAndroid Build Coastguard Worker char *
loader_get_device_name_for_fd(int fd)660*61046927SAndroid Build Coastguard Worker loader_get_device_name_for_fd(int fd)
661*61046927SAndroid Build Coastguard Worker {
662*61046927SAndroid Build Coastguard Worker    return drmGetDeviceNameFromFd2(fd);
663*61046927SAndroid Build Coastguard Worker }
664*61046927SAndroid Build Coastguard Worker 
665*61046927SAndroid Build Coastguard Worker static char *
loader_get_pci_driver(int fd)666*61046927SAndroid Build Coastguard Worker loader_get_pci_driver(int fd)
667*61046927SAndroid Build Coastguard Worker {
668*61046927SAndroid Build Coastguard Worker    int vendor_id, chip_id, i, j;
669*61046927SAndroid Build Coastguard Worker    char *driver = NULL;
670*61046927SAndroid Build Coastguard Worker 
671*61046927SAndroid Build Coastguard Worker    if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id))
672*61046927SAndroid Build Coastguard Worker       return NULL;
673*61046927SAndroid Build Coastguard Worker 
674*61046927SAndroid Build Coastguard Worker    for (i = 0; i < ARRAY_SIZE(driver_map); i++) {
675*61046927SAndroid Build Coastguard Worker       if (vendor_id != driver_map[i].vendor_id)
676*61046927SAndroid Build Coastguard Worker          continue;
677*61046927SAndroid Build Coastguard Worker 
678*61046927SAndroid Build Coastguard Worker       if (driver_map[i].predicate && !driver_map[i].predicate(fd, driver_map[i].driver))
679*61046927SAndroid Build Coastguard Worker          continue;
680*61046927SAndroid Build Coastguard Worker 
681*61046927SAndroid Build Coastguard Worker       if (driver_map[i].num_chips_ids == -1) {
682*61046927SAndroid Build Coastguard Worker          driver = strdup(driver_map[i].driver);
683*61046927SAndroid Build Coastguard Worker          goto out;
684*61046927SAndroid Build Coastguard Worker       }
685*61046927SAndroid Build Coastguard Worker 
686*61046927SAndroid Build Coastguard Worker       for (j = 0; j < driver_map[i].num_chips_ids; j++)
687*61046927SAndroid Build Coastguard Worker          if (driver_map[i].chip_ids[j] == chip_id) {
688*61046927SAndroid Build Coastguard Worker             driver = strdup(driver_map[i].driver);
689*61046927SAndroid Build Coastguard Worker             goto out;
690*61046927SAndroid Build Coastguard Worker          }
691*61046927SAndroid Build Coastguard Worker    }
692*61046927SAndroid Build Coastguard Worker 
693*61046927SAndroid Build Coastguard Worker out:
694*61046927SAndroid Build Coastguard Worker    log_(driver ? _LOADER_DEBUG : _LOADER_WARNING,
695*61046927SAndroid Build Coastguard Worker          "pci id for fd %d: %04x:%04x, driver %s\n",
696*61046927SAndroid Build Coastguard Worker          fd, vendor_id, chip_id, driver);
697*61046927SAndroid Build Coastguard Worker    return driver;
698*61046927SAndroid Build Coastguard Worker }
699*61046927SAndroid Build Coastguard Worker 
700*61046927SAndroid Build Coastguard Worker char *
loader_get_driver_for_fd(int fd)701*61046927SAndroid Build Coastguard Worker loader_get_driver_for_fd(int fd)
702*61046927SAndroid Build Coastguard Worker {
703*61046927SAndroid Build Coastguard Worker    char *driver;
704*61046927SAndroid Build Coastguard Worker 
705*61046927SAndroid Build Coastguard Worker    /* Allow an environment variable to force choosing a different driver
706*61046927SAndroid Build Coastguard Worker     * binary.  If that driver binary can't survive on this FD, that's the
707*61046927SAndroid Build Coastguard Worker     * user's problem, but this allows vc4 simulator to run on an i965 host,
708*61046927SAndroid Build Coastguard Worker     * and may be useful for some touch testing of i915 on an i965 host.
709*61046927SAndroid Build Coastguard Worker     */
710*61046927SAndroid Build Coastguard Worker    if (__normal_user()) {
711*61046927SAndroid Build Coastguard Worker       const char *override = os_get_option("MESA_LOADER_DRIVER_OVERRIDE");
712*61046927SAndroid Build Coastguard Worker       if (override)
713*61046927SAndroid Build Coastguard Worker          return strdup(override);
714*61046927SAndroid Build Coastguard Worker    }
715*61046927SAndroid Build Coastguard Worker 
716*61046927SAndroid Build Coastguard Worker #if defined(USE_DRICONF)
717*61046927SAndroid Build Coastguard Worker    driver = loader_get_dri_config_driver(fd);
718*61046927SAndroid Build Coastguard Worker    if (driver)
719*61046927SAndroid Build Coastguard Worker       return driver;
720*61046927SAndroid Build Coastguard Worker #endif
721*61046927SAndroid Build Coastguard Worker 
722*61046927SAndroid Build Coastguard Worker    driver = loader_get_pci_driver(fd);
723*61046927SAndroid Build Coastguard Worker    if (!driver)
724*61046927SAndroid Build Coastguard Worker       driver = loader_get_kernel_driver_name(fd);
725*61046927SAndroid Build Coastguard Worker 
726*61046927SAndroid Build Coastguard Worker    return driver;
727*61046927SAndroid Build Coastguard Worker }
728*61046927SAndroid Build Coastguard Worker 
729*61046927SAndroid Build Coastguard Worker void
loader_set_logger(loader_logger * logger)730*61046927SAndroid Build Coastguard Worker loader_set_logger(loader_logger *logger)
731*61046927SAndroid Build Coastguard Worker {
732*61046927SAndroid Build Coastguard Worker    log_ = logger;
733*61046927SAndroid Build Coastguard Worker }
734*61046927SAndroid Build Coastguard Worker 
735*61046927SAndroid Build Coastguard Worker bool
loader_bind_extensions(void * data,const struct dri_extension_match * matches,size_t num_matches,const __DRIextension ** extensions)736*61046927SAndroid Build Coastguard Worker loader_bind_extensions(void *data,
737*61046927SAndroid Build Coastguard Worker                        const struct dri_extension_match *matches, size_t num_matches,
738*61046927SAndroid Build Coastguard Worker                        const __DRIextension **extensions)
739*61046927SAndroid Build Coastguard Worker {
740*61046927SAndroid Build Coastguard Worker    bool ret = true;
741*61046927SAndroid Build Coastguard Worker 
742*61046927SAndroid Build Coastguard Worker    for (size_t j = 0; j < num_matches; j++) {
743*61046927SAndroid Build Coastguard Worker       const struct dri_extension_match *match = &matches[j];
744*61046927SAndroid Build Coastguard Worker       const __DRIextension **field = (const __DRIextension **)((char *)data + matches[j].offset);
745*61046927SAndroid Build Coastguard Worker       for (size_t i = 0; extensions[i]; i++) {
746*61046927SAndroid Build Coastguard Worker          if (strcmp(extensions[i]->name, match->name) == 0 &&
747*61046927SAndroid Build Coastguard Worker              extensions[i]->version >= match->version) {
748*61046927SAndroid Build Coastguard Worker             *field = extensions[i];
749*61046927SAndroid Build Coastguard Worker             break;
750*61046927SAndroid Build Coastguard Worker          }
751*61046927SAndroid Build Coastguard Worker       }
752*61046927SAndroid Build Coastguard Worker 
753*61046927SAndroid Build Coastguard Worker       if (!*field) {
754*61046927SAndroid Build Coastguard Worker          log_(match->optional ? _LOADER_DEBUG : _LOADER_FATAL, "did not find extension %s version %d\n",
755*61046927SAndroid Build Coastguard Worker                match->name, match->version);
756*61046927SAndroid Build Coastguard Worker          if (!match->optional)
757*61046927SAndroid Build Coastguard Worker             ret = false;
758*61046927SAndroid Build Coastguard Worker          continue;
759*61046927SAndroid Build Coastguard Worker       }
760*61046927SAndroid Build Coastguard Worker 
761*61046927SAndroid Build Coastguard Worker       /* The loaders rely on the loaded DRI drivers being from the same Mesa
762*61046927SAndroid Build Coastguard Worker        * build so that we can reference the same structs on both sides.
763*61046927SAndroid Build Coastguard Worker        */
764*61046927SAndroid Build Coastguard Worker       if (strcmp(match->name, __DRI_MESA) == 0) {
765*61046927SAndroid Build Coastguard Worker          const __DRImesaCoreExtension *mesa = (const __DRImesaCoreExtension *)*field;
766*61046927SAndroid Build Coastguard Worker          if (strcmp(mesa->version_string, MESA_INTERFACE_VERSION_STRING) != 0) {
767*61046927SAndroid Build Coastguard Worker             log_(_LOADER_FATAL, "DRI driver not from this Mesa build ('%s' vs '%s')\n",
768*61046927SAndroid Build Coastguard Worker                  mesa->version_string, MESA_INTERFACE_VERSION_STRING);
769*61046927SAndroid Build Coastguard Worker             ret = false;
770*61046927SAndroid Build Coastguard Worker          }
771*61046927SAndroid Build Coastguard Worker       }
772*61046927SAndroid Build Coastguard Worker    }
773*61046927SAndroid Build Coastguard Worker 
774*61046927SAndroid Build Coastguard Worker    return ret;
775*61046927SAndroid Build Coastguard Worker }
776*61046927SAndroid Build Coastguard Worker /**
777*61046927SAndroid Build Coastguard Worker  * Opens a driver or backend using its name, returning the library handle.
778*61046927SAndroid Build Coastguard Worker  *
779*61046927SAndroid Build Coastguard Worker  * \param driverName - a name like "i965", "radeon", "nouveau", etc.
780*61046927SAndroid Build Coastguard Worker  * \param lib_suffix - a suffix to append to the driver name to generate the
781*61046927SAndroid Build Coastguard Worker  * full library name.
782*61046927SAndroid Build Coastguard Worker  * \param search_path_vars - NULL-terminated list of env vars that can be used
783*61046927SAndroid Build Coastguard Worker  * \param default_search_path - a colon-separted list of directories used if
784*61046927SAndroid Build Coastguard Worker  * search_path_vars is NULL or none of the vars are set in the environment.
785*61046927SAndroid Build Coastguard Worker  * \param warn_on_fail - Log a warning if the driver is not found.
786*61046927SAndroid Build Coastguard Worker  */
787*61046927SAndroid Build Coastguard Worker void *
loader_open_driver_lib(const char * driver_name,const char * lib_suffix,const char ** search_path_vars,const char * default_search_path,bool warn_on_fail)788*61046927SAndroid Build Coastguard Worker loader_open_driver_lib(const char *driver_name,
789*61046927SAndroid Build Coastguard Worker                        const char *lib_suffix,
790*61046927SAndroid Build Coastguard Worker                        const char **search_path_vars,
791*61046927SAndroid Build Coastguard Worker                        const char *default_search_path,
792*61046927SAndroid Build Coastguard Worker                        bool warn_on_fail)
793*61046927SAndroid Build Coastguard Worker {
794*61046927SAndroid Build Coastguard Worker    char path[PATH_MAX];
795*61046927SAndroid Build Coastguard Worker    const char *search_paths, *next, *end;
796*61046927SAndroid Build Coastguard Worker 
797*61046927SAndroid Build Coastguard Worker    search_paths = NULL;
798*61046927SAndroid Build Coastguard Worker    if (__normal_user() && search_path_vars) {
799*61046927SAndroid Build Coastguard Worker       for (int i = 0; search_path_vars[i] != NULL; i++) {
800*61046927SAndroid Build Coastguard Worker          search_paths = os_get_option(search_path_vars[i]);
801*61046927SAndroid Build Coastguard Worker          if (search_paths)
802*61046927SAndroid Build Coastguard Worker             break;
803*61046927SAndroid Build Coastguard Worker       }
804*61046927SAndroid Build Coastguard Worker    }
805*61046927SAndroid Build Coastguard Worker    if (search_paths == NULL)
806*61046927SAndroid Build Coastguard Worker       search_paths = default_search_path;
807*61046927SAndroid Build Coastguard Worker 
808*61046927SAndroid Build Coastguard Worker    void *driver = NULL;
809*61046927SAndroid Build Coastguard Worker    const char *dl_error = NULL;
810*61046927SAndroid Build Coastguard Worker    end = search_paths + strlen(search_paths);
811*61046927SAndroid Build Coastguard Worker    for (const char *p = search_paths; p < end; p = next + 1) {
812*61046927SAndroid Build Coastguard Worker       int len;
813*61046927SAndroid Build Coastguard Worker       next = strchr(p, ':');
814*61046927SAndroid Build Coastguard Worker       if (next == NULL)
815*61046927SAndroid Build Coastguard Worker          next = end;
816*61046927SAndroid Build Coastguard Worker 
817*61046927SAndroid Build Coastguard Worker       len = next - p;
818*61046927SAndroid Build Coastguard Worker       snprintf(path, sizeof(path), "%.*s/tls/%s%s.so", len,
819*61046927SAndroid Build Coastguard Worker                p, driver_name, lib_suffix);
820*61046927SAndroid Build Coastguard Worker       driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
821*61046927SAndroid Build Coastguard Worker       if (driver == NULL) {
822*61046927SAndroid Build Coastguard Worker          snprintf(path, sizeof(path), "%.*s/%s%s.so", len,
823*61046927SAndroid Build Coastguard Worker                   p, driver_name, lib_suffix);
824*61046927SAndroid Build Coastguard Worker          driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
825*61046927SAndroid Build Coastguard Worker          if (driver == NULL) {
826*61046927SAndroid Build Coastguard Worker             dl_error = dlerror();
827*61046927SAndroid Build Coastguard Worker             log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n",
828*61046927SAndroid Build Coastguard Worker                  path, dl_error);
829*61046927SAndroid Build Coastguard Worker          }
830*61046927SAndroid Build Coastguard Worker       }
831*61046927SAndroid Build Coastguard Worker       /* not need continue to loop all paths once the driver is found */
832*61046927SAndroid Build Coastguard Worker       if (driver != NULL)
833*61046927SAndroid Build Coastguard Worker          break;
834*61046927SAndroid Build Coastguard Worker    }
835*61046927SAndroid Build Coastguard Worker 
836*61046927SAndroid Build Coastguard Worker    if (driver == NULL) {
837*61046927SAndroid Build Coastguard Worker       if (warn_on_fail) {
838*61046927SAndroid Build Coastguard Worker          log_(_LOADER_WARNING,
839*61046927SAndroid Build Coastguard Worker               "MESA-LOADER: failed to open %s: %s (search paths %s, suffix %s)\n",
840*61046927SAndroid Build Coastguard Worker               driver_name, dl_error, search_paths, lib_suffix);
841*61046927SAndroid Build Coastguard Worker       }
842*61046927SAndroid Build Coastguard Worker       return NULL;
843*61046927SAndroid Build Coastguard Worker    }
844*61046927SAndroid Build Coastguard Worker 
845*61046927SAndroid Build Coastguard Worker    log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path);
846*61046927SAndroid Build Coastguard Worker 
847*61046927SAndroid Build Coastguard Worker    return driver;
848*61046927SAndroid Build Coastguard Worker }
849