2 * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
4 * This code is derived from the following files.
6 * * src/glx/dri3_common.c
7 * Copyright © 2013 Keith Packard
9 * * src/egl/drivers/dri2/common.c
10 * * src/gbm/backends/dri/driver_name.c
11 * Copyright © 2011 Intel Corporation
14 * Kristian Høgsberg <krh@bitplanet.net>
15 * Benjamin Franzke <benjaminfranzke@googlemail.com>
17 * * src/gallium/targets/egl-static/egl.c
18 * Copyright (C) 2010-2011 LunarG Inc.
21 * Chia-I Wu <olv@lunarg.com>
23 * * src/gallium/state_trackers/egl/drm/native_drm.c
24 * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
26 * * src/egl/drivers/dri2/platform_android.c
28 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
29 * Copyright (C) 2010-2011 LunarG Inc.
31 * Based on platform_x11, which has
33 * Copyright © 2011 Intel Corporation
35 * * src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
36 * Copyright 2011 Intel Corporation
37 * Copyright 2012 Francisco Jerez
38 * All Rights Reserved.
41 * Kristian Høgsberg <krh@bitplanet.net>
42 * Benjamin Franzke <benjaminfranzke@googlemail.com>
44 * Permission is hereby granted, free of charge, to any person obtaining a
45 * copy of this software and associated documentation files (the "Software"),
46 * to deal in the Software without restriction, including without limitation
47 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
48 * and/or sell copies of the Software, and to permit persons to whom the
49 * Software is furnished to do so, subject to the following conditions:
51 * The above copyright notice and this permission notice (including the next
52 * paragraph) shall be included in all copies or substantial portions of the
55 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
58 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
64 * Rob Clark <robclark@freedesktop.org>
75 #include <sys/mkdev.h>
77 #ifdef MAJOR_IN_SYSMACROS
78 #include <sys/sysmacros.h>
87 #include "xmlconfig.h"
93 #include "pci_id_driver_map.h"
95 static void default_logger(int level
, const char *fmt
, ...)
97 if (level
<= _LOADER_WARNING
) {
100 vfprintf(stderr
, fmt
, args
);
105 static void (*log_
)(int level
, const char *fmt
, ...) = default_logger
;
108 loader_open_device(const char *device_name
)
112 fd
= open(device_name
, O_RDWR
| O_CLOEXEC
);
113 if (fd
== -1 && errno
== EINVAL
)
116 fd
= open(device_name
, O_RDWR
);
118 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
123 #if defined(HAVE_LIBDRM)
125 static const char __driConfigOptionsLoader
[] =
127 DRI_CONF_SECTION_INITIALIZATION
128 DRI_CONF_DEVICE_ID_PATH_TAG()
132 static char *loader_get_dri_config_device_id(void)
134 driOptionCache defaultInitOptions
;
135 driOptionCache userInitOptions
;
138 driParseOptionInfo(&defaultInitOptions
, __driConfigOptionsLoader
);
139 driParseConfigFiles(&userInitOptions
, &defaultInitOptions
, 0, "loader");
140 if (driCheckOption(&userInitOptions
, "device_id", DRI_STRING
))
141 prime
= strdup(driQueryOptionstr(&userInitOptions
, "device_id"));
142 driDestroyOptionCache(&userInitOptions
);
143 driDestroyOptionInfo(&defaultInitOptions
);
149 static char *drm_construct_id_path_tag(drmDevicePtr device
)
151 /* Length of "pci-xxxx_xx_xx_x\0" */
152 #define PCI_ID_PATH_TAG_LENGTH 17
155 if (device
->bustype
== DRM_BUS_PCI
) {
156 tag
= calloc(PCI_ID_PATH_TAG_LENGTH
, sizeof(char));
160 snprintf(tag
, PCI_ID_PATH_TAG_LENGTH
, "pci-%04x_%02x_%02x_%1u",
161 device
->businfo
.pci
->domain
, device
->businfo
.pci
->bus
,
162 device
->businfo
.pci
->dev
, device
->businfo
.pci
->func
);
167 static bool drm_device_matches_tag(drmDevicePtr device
, const char *prime_tag
)
169 char *tag
= drm_construct_id_path_tag(device
);
175 ret
= strcmp(tag
, prime_tag
);
181 static char *drm_get_id_path_tag_for_fd(int fd
)
186 if (drmGetDevice(fd
, &device
) != 0)
189 tag
= drm_construct_id_path_tag(device
);
190 drmFreeDevice(&device
);
194 int loader_get_user_preferred_fd(int default_fd
, int *different_device
)
196 /* Arbitrary "maximum" value of drm devices. */
197 #define MAX_DRM_DEVICES 32
198 const char *dri_prime
= getenv("DRI_PRIME");
199 char *default_tag
, *prime
= NULL
;
200 drmDevicePtr devices
[MAX_DRM_DEVICES
];
201 int i
, num_devices
, fd
;
205 prime
= strdup(dri_prime
);
208 prime
= loader_get_dri_config_device_id();
212 *different_device
= 0;
216 default_tag
= drm_get_id_path_tag_for_fd(default_fd
);
217 if (default_tag
== NULL
)
220 num_devices
= drmGetDevices(devices
, MAX_DRM_DEVICES
);
224 /* two format are supported:
225 * "1": choose any other card than the card used by default.
226 * id_path_tag: (for example "pci-0000_02_00_0") choose the card
227 * with this id_path_tag.
229 if (!strcmp(prime
,"1")) {
230 /* Hmm... detection for 2-7 seems to be broken. Oh well ...
231 * Pick the first render device that is not our own.
233 for (i
= 0; i
< num_devices
; i
++) {
234 if (devices
[i
]->available_nodes
& 1 << DRM_NODE_RENDER
&&
235 !drm_device_matches_tag(devices
[i
], default_tag
)) {
242 for (i
= 0; i
< num_devices
; i
++) {
243 if (devices
[i
]->available_nodes
& 1 << DRM_NODE_RENDER
&&
244 drm_device_matches_tag(devices
[i
], prime
)) {
253 drmFreeDevices(devices
, num_devices
);
257 fd
= loader_open_device(devices
[i
]->nodes
[DRM_NODE_RENDER
]);
258 drmFreeDevices(devices
, num_devices
);
264 *different_device
= !!strcmp(default_tag
, prime
);
271 *different_device
= 0;
278 int loader_get_user_preferred_fd(int default_fd
, int *different_device
)
280 *different_device
= 0;
285 #if defined(HAVE_LIBDRM)
287 dev_node_from_fd(int fd
, unsigned int *maj
, unsigned int *min
)
291 if (fstat(fd
, &buf
) < 0) {
292 log_(_LOADER_WARNING
, "MESA-LOADER: failed to stat fd %d\n", fd
);
296 if (!S_ISCHR(buf
.st_mode
)) {
297 log_(_LOADER_WARNING
, "MESA-LOADER: fd %d not a character device\n", fd
);
301 *maj
= major(buf
.st_rdev
);
302 *min
= minor(buf
.st_rdev
);
308 #if defined(HAVE_LIBDRM)
311 drm_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
316 if (drmGetDevice(fd
, &device
) == 0) {
317 if (device
->bustype
== DRM_BUS_PCI
) {
318 *vendor_id
= device
->deviceinfo
.pci
->vendor_id
;
319 *chip_id
= device
->deviceinfo
.pci
->device_id
;
323 log_(_LOADER_WARNING
, "MESA-LOADER: device is not located on the PCI bus\n");
326 drmFreeDevice(&device
);
329 log_(_LOADER_WARNING
, "MESA-LOADER: failed to retrieve device information\n");
339 loader_get_pci_id_for_fd(int fd
, int *vendor_id
, int *chip_id
)
342 if (drm_get_pci_id_for_fd(fd
, vendor_id
, chip_id
))
349 #if defined(HAVE_LIBDRM)
351 drm_get_device_name_for_fd(int fd
)
353 unsigned int maj
, min
;
357 if (dev_node_from_fd(fd
, &maj
, &min
) < 0)
360 n
= snprintf(buf
, sizeof(buf
), DRM_DEV_NAME
, DRM_DIR_NAME
, min
);
361 if (n
== -1 || n
>= sizeof(buf
))
369 loader_get_device_name_for_fd(int fd
)
374 if ((result
= drm_get_device_name_for_fd(fd
)))
381 loader_get_driver_for_fd(int fd
, unsigned driver_types
)
383 int vendor_id
, chip_id
, i
, j
;
387 driver_types
= _LOADER_GALLIUM
| _LOADER_DRI
;
389 if (!loader_get_pci_id_for_fd(fd
, &vendor_id
, &chip_id
)) {
392 /* fallback to drmGetVersion(): */
393 drmVersionPtr version
= drmGetVersion(fd
);
396 log_(_LOADER_WARNING
, "failed to get driver name for fd %d\n", fd
);
400 driver
= strndup(version
->name
, version
->name_len
);
401 log_(_LOADER_INFO
, "using driver %s for %d\n", driver
, fd
);
403 drmFreeVersion(version
);
409 for (i
= 0; driver_map
[i
].driver
; i
++) {
410 if (vendor_id
!= driver_map
[i
].vendor_id
)
413 if (!(driver_types
& driver_map
[i
].driver_types
))
416 if (driver_map
[i
].predicate
&& !driver_map
[i
].predicate(fd
))
419 if (driver_map
[i
].num_chips_ids
== -1) {
420 driver
= strdup(driver_map
[i
].driver
);
424 for (j
= 0; j
< driver_map
[i
].num_chips_ids
; j
++)
425 if (driver_map
[i
].chip_ids
[j
] == chip_id
) {
426 driver
= strdup(driver_map
[i
].driver
);
432 log_(driver
? _LOADER_DEBUG
: _LOADER_WARNING
,
433 "pci id for fd %d: %04x:%04x, driver %s\n",
434 fd
, vendor_id
, chip_id
, driver
);
439 loader_set_logger(void (*logger
)(int level
, const char *fmt
, ...))