103b705cfSriastradh/*************************************************************************** 203b705cfSriastradh 303b705cfSriastradh Copyright 2013 Intel Corporation. All Rights Reserved. 403b705cfSriastradh 503b705cfSriastradh Permission is hereby granted, free of charge, to any person obtaining a 603b705cfSriastradh copy of this software and associated documentation files (the 703b705cfSriastradh "Software"), to deal in the Software without restriction, including 803b705cfSriastradh without limitation the rights to use, copy, modify, merge, publish, 903b705cfSriastradh distribute, sub license, and/or sell copies of the Software, and to 1003b705cfSriastradh permit persons to whom the Software is furnished to do so, subject to 1103b705cfSriastradh the following conditions: 1203b705cfSriastradh 1303b705cfSriastradh The above copyright notice and this permission notice (including the 1403b705cfSriastradh next paragraph) shall be included in all copies or substantial portions 1503b705cfSriastradh of the Software. 1603b705cfSriastradh 1703b705cfSriastradh THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1803b705cfSriastradh OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1903b705cfSriastradh MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2003b705cfSriastradh IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2103b705cfSriastradh DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2203b705cfSriastradh OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 2303b705cfSriastradh THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2403b705cfSriastradh 2503b705cfSriastradh **************************************************************************/ 2603b705cfSriastradh 2742542f5fSchristos#ifdef HAVE_CONFIG_H 2842542f5fSchristos#include "config.h" 2942542f5fSchristos#endif 3042542f5fSchristos 3142542f5fSchristos#include <sys/types.h> 3242542f5fSchristos#include <sys/stat.h> 3303b705cfSriastradh#include <assert.h> 3403b705cfSriastradh#include <string.h> 3503b705cfSriastradh#include <unistd.h> 3603b705cfSriastradh#include <fcntl.h> 3703b705cfSriastradh#include <stdlib.h> 3842542f5fSchristos#include <dirent.h> 3903b705cfSriastradh#include <errno.h> 4003b705cfSriastradh 41fe8aea9eSmrg#if MAJOR_IN_MKDEV 42fe8aea9eSmrg#include <sys/mkdev.h> 43fe8aea9eSmrg#elif MAJOR_IN_SYSMACROS 44fe8aea9eSmrg#include <sys/sysmacros.h> 45fe8aea9eSmrg#endif 46fe8aea9eSmrg 4703b705cfSriastradh#include <pciaccess.h> 4842542f5fSchristos 4942542f5fSchristos#include <xorg-server.h> 5003b705cfSriastradh#include <xf86.h> 5103b705cfSriastradh#include <xf86drm.h> 5203b705cfSriastradh#include <xf86drmMode.h> 5303b705cfSriastradh#include <xf86_OSproc.h> 5403b705cfSriastradh#include <i915_drm.h> 5503b705cfSriastradh 5642542f5fSchristos#ifdef XSERVER_PLATFORM_BUS 5742542f5fSchristos#include <xf86platformBus.h> 5842542f5fSchristos#endif 5942542f5fSchristos 6042542f5fSchristos#ifdef HAVE_VALGRIND 6142542f5fSchristos#include <valgrind.h> 6242542f5fSchristos#include <memcheck.h> 6342542f5fSchristos#define VG(x) x 6442542f5fSchristos#else 6542542f5fSchristos#define VG(x) 6642542f5fSchristos#endif 6742542f5fSchristos 6842542f5fSchristos#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) 6942542f5fSchristos 7003b705cfSriastradh#include "intel_driver.h" 7142542f5fSchristos#include "fd.h" 7203b705cfSriastradh 7303b705cfSriastradhstruct intel_device { 7413496ba1Ssnj int idx; 7542542f5fSchristos char *master_node; 7642542f5fSchristos char *render_node; 7703b705cfSriastradh int fd; 7813496ba1Ssnj int device_id; 7903b705cfSriastradh int open_count; 8003b705cfSriastradh int master_count; 8103b705cfSriastradh}; 8203b705cfSriastradh 8303b705cfSriastradhstatic int intel_device_key = -1; 8403b705cfSriastradh 8542542f5fSchristosstatic int dump_file(ScrnInfoPtr scrn, const char *path) 8642542f5fSchristos{ 8742542f5fSchristos FILE *file; 8842542f5fSchristos size_t len = 0; 8942542f5fSchristos char *line = NULL; 9042542f5fSchristos 9142542f5fSchristos file = fopen(path, "r"); 9242542f5fSchristos if (file == NULL) 9342542f5fSchristos return 0; 9442542f5fSchristos 9542542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] Contents of '%s':\n", path); 9642542f5fSchristos while (getline(&line, &len, file) != -1) 9742542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] %s", line); 9842542f5fSchristos 9942542f5fSchristos free(line); 10042542f5fSchristos fclose(file); 10142542f5fSchristos return 1; 10242542f5fSchristos} 10342542f5fSchristos 10442542f5fSchristosstatic int __find_debugfs(void) 10542542f5fSchristos{ 10642542f5fSchristos int i; 10742542f5fSchristos 10842542f5fSchristos for (i = 0; i < DRM_MAX_MINOR; i++) { 10942542f5fSchristos char path[80]; 11042542f5fSchristos 11142542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 11242542f5fSchristos if (access(path, R_OK) == 0) 11342542f5fSchristos return i; 11442542f5fSchristos 11542542f5fSchristos sprintf(path, "/debug/dri/%d/i915_wedged", i); 11642542f5fSchristos if (access(path, R_OK) == 0) 11742542f5fSchristos return i; 11842542f5fSchristos } 11942542f5fSchristos 12042542f5fSchristos return -1; 12142542f5fSchristos} 12242542f5fSchristos 12342542f5fSchristosstatic int drm_get_minor(int fd) 12442542f5fSchristos{ 12542542f5fSchristos struct stat st; 12642542f5fSchristos 12742542f5fSchristos if (fstat(fd, &st)) 12842542f5fSchristos return __find_debugfs(); 12942542f5fSchristos 13042542f5fSchristos if (!S_ISCHR(st.st_mode)) 13142542f5fSchristos return __find_debugfs(); 13242542f5fSchristos 13342542f5fSchristos return st.st_rdev & 0x63; 13442542f5fSchristos} 13542542f5fSchristos 13642542f5fSchristos#if __linux__ 13742542f5fSchristos#include <sys/mount.h> 13842542f5fSchristos 13942542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) 14042542f5fSchristos{ 14142542f5fSchristos char path[80]; 14242542f5fSchristos int minor; 14342542f5fSchristos 14442542f5fSchristos minor = drm_get_minor(fd); 14542542f5fSchristos if (minor < 0) 14642542f5fSchristos return; 14742542f5fSchristos 14842542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 14942542f5fSchristos if (dump_file(scrn, path)) 15042542f5fSchristos return; 15142542f5fSchristos 15242542f5fSchristos sprintf(path, "/debug/dri/%d/%s", minor, name); 15342542f5fSchristos if (dump_file(scrn, path)) 15442542f5fSchristos return; 15542542f5fSchristos 15642542f5fSchristos if (mount("X-debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0) { 15742542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 15842542f5fSchristos dump_file(scrn, path); 15942542f5fSchristos umount("X-debug"); 16042542f5fSchristos return; 16142542f5fSchristos } 16242542f5fSchristos} 16342542f5fSchristos#else 16442542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) { } 16542542f5fSchristos#endif 16642542f5fSchristos 16742542f5fSchristosstatic void dump_clients_info(ScrnInfoPtr scrn, int fd) 16842542f5fSchristos{ 16942542f5fSchristos dump_debugfs(scrn, fd, "clients"); 17042542f5fSchristos} 17142542f5fSchristos 17242542f5fSchristosstatic int __intel_get_device_id(int fd) 17342542f5fSchristos{ 17442542f5fSchristos struct drm_i915_getparam gp; 17542542f5fSchristos int devid = 0; 17642542f5fSchristos 17742542f5fSchristos VG_CLEAR(gp); 17842542f5fSchristos gp.param = I915_PARAM_CHIPSET_ID; 17942542f5fSchristos gp.value = &devid; 18042542f5fSchristos 18142542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 18242542f5fSchristos return 0; 18342542f5fSchristos 18442542f5fSchristos return devid; 18542542f5fSchristos} 18642542f5fSchristos 18742542f5fSchristosint intel_entity_get_devid(int idx) 18842542f5fSchristos{ 18942542f5fSchristos struct intel_device *dev; 19042542f5fSchristos 19142542f5fSchristos dev = xf86GetEntityPrivate(idx, intel_device_key)->ptr; 19242542f5fSchristos if (dev == NULL) 19342542f5fSchristos return 0; 19442542f5fSchristos 19513496ba1Ssnj return dev->device_id; 19642542f5fSchristos} 19742542f5fSchristos 19803b705cfSriastradhstatic inline struct intel_device *intel_device(ScrnInfoPtr scrn) 19903b705cfSriastradh{ 20003b705cfSriastradh if (scrn->entityList == NULL) 20103b705cfSriastradh return NULL; 20203b705cfSriastradh 20303b705cfSriastradh return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 20403b705cfSriastradh} 20503b705cfSriastradh 206fe8aea9eSmrgstatic const char *kernel_module_names[] ={ 207fe8aea9eSmrg "i915", 208fe8aea9eSmrg NULL, 209fe8aea9eSmrg}; 210fe8aea9eSmrg 21142542f5fSchristosstatic int is_i915_device(int fd) 21203b705cfSriastradh{ 21303b705cfSriastradh drm_version_t version; 214fe8aea9eSmrg const char **kn; 21503b705cfSriastradh char name[5] = ""; 21603b705cfSriastradh 21703b705cfSriastradh memset(&version, 0, sizeof(version)); 21803b705cfSriastradh version.name_len = 4; 21903b705cfSriastradh version.name = name; 22003b705cfSriastradh 22103b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 22242542f5fSchristos return 0; 22303b705cfSriastradh 224fe8aea9eSmrg for (kn = kernel_module_names; *kn; kn++) 225fe8aea9eSmrg if (strcmp(*kn, name) == 0) 226fe8aea9eSmrg return 1; 227fe8aea9eSmrg 228fe8aea9eSmrg return 0; 229fe8aea9eSmrg} 230fe8aea9eSmrg 231fe8aea9eSmrgstatic int load_i915_kernel_module(void) 232fe8aea9eSmrg{ 233fe8aea9eSmrg const char **kn; 234fe8aea9eSmrg 235fe8aea9eSmrg for (kn = kernel_module_names; *kn; kn++) 236fe8aea9eSmrg if (xf86LoadKernelModule(*kn)) 237fe8aea9eSmrg return 0; 238fe8aea9eSmrg 239fe8aea9eSmrg return -1; 24003b705cfSriastradh} 24103b705cfSriastradh 24242542f5fSchristosstatic int is_i915_gem(int fd) 24303b705cfSriastradh{ 24442542f5fSchristos int ret = is_i915_device(fd); 24503b705cfSriastradh 24603b705cfSriastradh if (ret) { 24703b705cfSriastradh struct drm_i915_getparam gp; 24842542f5fSchristos 24942542f5fSchristos VG_CLEAR(gp); 25003b705cfSriastradh gp.param = I915_PARAM_HAS_GEM; 25103b705cfSriastradh gp.value = &ret; 25242542f5fSchristos 25303b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 25442542f5fSchristos ret = 0; 25503b705cfSriastradh } 25642542f5fSchristos 25742542f5fSchristos return ret; 25842542f5fSchristos} 25942542f5fSchristos 26042542f5fSchristosstatic int __intel_check_device(int fd) 26142542f5fSchristos{ 26242542f5fSchristos int ret; 26342542f5fSchristos 26442542f5fSchristos /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 26542542f5fSchristos ret = is_i915_gem(fd); 26603b705cfSriastradh if (ret && !hosted()) { 26703b705cfSriastradh struct drm_mode_card_res res; 26803b705cfSriastradh 26903b705cfSriastradh memset(&res, 0, sizeof(res)); 27003b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 27142542f5fSchristos ret = 0; 27203b705cfSriastradh } 27303b705cfSriastradh 27403b705cfSriastradh return ret; 27503b705cfSriastradh} 27603b705cfSriastradh 27742542f5fSchristosstatic int open_cloexec(const char *path) 27803b705cfSriastradh{ 27942542f5fSchristos struct stat st; 28042542f5fSchristos int loop = 1000; 28142542f5fSchristos int fd; 28203b705cfSriastradh 28342542f5fSchristos /* No file? Assume the driver is loading slowly */ 28442542f5fSchristos while (stat(path, &st) == -1 && errno == ENOENT && --loop) 28542542f5fSchristos usleep(50000); 28642542f5fSchristos 28742542f5fSchristos if (loop != 1000) 28842542f5fSchristos ErrorF("intel: waited %d ms for '%s' to appear\n", 28942542f5fSchristos (1000 - loop) * 50, path); 29042542f5fSchristos 29142542f5fSchristos fd = -1; 29242542f5fSchristos#ifdef O_CLOEXEC 29342542f5fSchristos fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC); 29442542f5fSchristos#endif 29503b705cfSriastradh if (fd == -1) 29642542f5fSchristos fd = fd_set_cloexec(open(path, O_RDWR | O_NONBLOCK)); 29703b705cfSriastradh 29842542f5fSchristos return fd; 29942542f5fSchristos} 30042542f5fSchristos 30142542f5fSchristos#ifdef __linux__ 30242542f5fSchristosstatic int __intel_open_device__major_minor(int _major, int _minor) 30342542f5fSchristos{ 30442542f5fSchristos char path[256]; 30542542f5fSchristos DIR *dir; 30642542f5fSchristos struct dirent *de; 30742542f5fSchristos int base, fd = -1; 30842542f5fSchristos 30942542f5fSchristos base = sprintf(path, "/dev/dri/"); 31042542f5fSchristos 31142542f5fSchristos dir = opendir(path); 31242542f5fSchristos if (dir == NULL) 31342542f5fSchristos return -1; 31442542f5fSchristos 31542542f5fSchristos while ((de = readdir(dir)) != NULL) { 31642542f5fSchristos struct stat st; 31742542f5fSchristos 31842542f5fSchristos if (*de->d_name == '.') 31942542f5fSchristos continue; 32042542f5fSchristos 32142542f5fSchristos sprintf(path + base, "%s", de->d_name); 32242542f5fSchristos if (stat(path, &st) == 0 && 32342542f5fSchristos major(st.st_rdev) == _major && 32442542f5fSchristos minor(st.st_rdev) == _minor) { 32542542f5fSchristos fd = open_cloexec(path); 32642542f5fSchristos break; 32742542f5fSchristos } 32803b705cfSriastradh } 32942542f5fSchristos 33042542f5fSchristos closedir(dir); 33103b705cfSriastradh 33203b705cfSriastradh return fd; 33303b705cfSriastradh} 33403b705cfSriastradh 33542542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) 33603b705cfSriastradh{ 33742542f5fSchristos struct stat st; 33842542f5fSchristos char path[256]; 33942542f5fSchristos DIR *dir; 34042542f5fSchristos struct dirent *de; 34142542f5fSchristos int base; 34203b705cfSriastradh int fd; 34303b705cfSriastradh 34442542f5fSchristos /* Look up the major:minor for the drm device through sysfs. 34542542f5fSchristos * First we need to check that sysfs is available, then 34642542f5fSchristos * check that we have loaded our driver. When we are happy 34742542f5fSchristos * that our KMS module is loaded, we can then search for our 34842542f5fSchristos * device node. We make the assumption that it uses the same 34942542f5fSchristos * name, but after that we read the major:minor assigned to us 35042542f5fSchristos * and search for a matching entry in /dev. 35142542f5fSchristos */ 35242542f5fSchristos 35342542f5fSchristos base = sprintf(path, 35442542f5fSchristos "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 35542542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 35642542f5fSchristos if (stat(path, &st)) 35742542f5fSchristos return -1; 35803b705cfSriastradh 35942542f5fSchristos sprintf(path + base, "drm"); 36042542f5fSchristos dir = opendir(path); 36142542f5fSchristos if (dir == NULL) { 36242542f5fSchristos int loop = 0; 36303b705cfSriastradh 36442542f5fSchristos sprintf(path + base, "driver"); 36542542f5fSchristos if (stat(path, &st)) { 366fe8aea9eSmrg if (load_i915_kernel_module()) 36703b705cfSriastradh return -1; 36803b705cfSriastradh (void)xf86LoadKernelModule("fbcon"); 36903b705cfSriastradh } 37003b705cfSriastradh 37142542f5fSchristos sprintf(path + base, "drm"); 37242542f5fSchristos while ((dir = opendir(path)) == NULL && loop++ < 100) 37342542f5fSchristos usleep(20000); 37442542f5fSchristos 37542542f5fSchristos ErrorF("intel: waited %d ms for i915.ko driver to load\n", loop * 20000 / 1000); 37642542f5fSchristos 37742542f5fSchristos if (dir == NULL) 37842542f5fSchristos return -1; 37942542f5fSchristos } 38042542f5fSchristos 38142542f5fSchristos fd = -1; 38242542f5fSchristos while ((de = readdir(dir)) != NULL) { 38342542f5fSchristos if (*de->d_name == '.') 38442542f5fSchristos continue; 38542542f5fSchristos 38642542f5fSchristos if (strncmp(de->d_name, "card", 4) == 0) { 38742542f5fSchristos sprintf(path + base + 4, "/dev/dri/%s", de->d_name); 38842542f5fSchristos fd = open_cloexec(path + base + 4); 38942542f5fSchristos if (fd != -1) 39042542f5fSchristos break; 39142542f5fSchristos 39242542f5fSchristos sprintf(path + base + 3, "/%s/dev", de->d_name); 39342542f5fSchristos fd = open(path, O_RDONLY); 39442542f5fSchristos if (fd == -1) 39542542f5fSchristos break; 39642542f5fSchristos 39742542f5fSchristos base = read(fd, path, sizeof(path) - 1); 39842542f5fSchristos close(fd); 39942542f5fSchristos 40042542f5fSchristos fd = -1; 40142542f5fSchristos if (base > 0) { 40242542f5fSchristos int major, minor; 40342542f5fSchristos path[base] = '\0'; 40442542f5fSchristos if (sscanf(path, "%d:%d", &major, &minor) == 2) 40542542f5fSchristos fd = __intel_open_device__major_minor(major, minor); 40603b705cfSriastradh } 40742542f5fSchristos break; 40803b705cfSriastradh } 40942542f5fSchristos } 41042542f5fSchristos closedir(dir); 41142542f5fSchristos 41242542f5fSchristos return fd; 41342542f5fSchristos} 41403b705cfSriastradh#else 41542542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) { return -1; } 41603b705cfSriastradh#endif 41742542f5fSchristos 41842542f5fSchristosstatic int __intel_open_device__legacy(const struct pci_device *pci) 41942542f5fSchristos{ 42042542f5fSchristos char id[20]; 42142542f5fSchristos int ret; 42242542f5fSchristos 42342542f5fSchristos snprintf(id, sizeof(id), 42442542f5fSchristos "pci:%04x:%02x:%02x.%d", 42542542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 42642542f5fSchristos 42742542f5fSchristos ret = drmCheckModesettingSupported(id); 42842542f5fSchristos if (ret) { 429fe8aea9eSmrg if (load_i915_kernel_module() == 0) 43042542f5fSchristos ret = drmCheckModesettingSupported(id); 43142542f5fSchristos if (ret) 43242542f5fSchristos return -1; 43342542f5fSchristos /* Be nice to the user and load fbcon too */ 43442542f5fSchristos (void)xf86LoadKernelModule("fbcon"); 43503b705cfSriastradh } 43603b705cfSriastradh 43742542f5fSchristos return fd_set_nonblock(drmOpen(NULL, id)); 43842542f5fSchristos} 43942542f5fSchristos 44042542f5fSchristosstatic int __intel_open_device(const struct pci_device *pci, const char *path) 44142542f5fSchristos{ 44242542f5fSchristos int fd; 44342542f5fSchristos 44442542f5fSchristos if (path == NULL) { 44542542f5fSchristos if (pci == NULL) 44642542f5fSchristos return -1; 44742542f5fSchristos 44842542f5fSchristos fd = __intel_open_device__pci(pci); 44942542f5fSchristos if (fd == -1) 45042542f5fSchristos fd = __intel_open_device__legacy(pci); 45142542f5fSchristos } else 45242542f5fSchristos fd = open_cloexec(path); 45342542f5fSchristos 45403b705cfSriastradh return fd; 45503b705cfSriastradh} 45603b705cfSriastradh 45742542f5fSchristosstatic char *find_master_node(int fd) 45842542f5fSchristos{ 45942542f5fSchristos struct stat st, master; 46042542f5fSchristos char buf[128]; 46142542f5fSchristos 46242542f5fSchristos if (fstat(fd, &st)) 46342542f5fSchristos return NULL; 46442542f5fSchristos 46542542f5fSchristos if (!S_ISCHR(st.st_mode)) 46642542f5fSchristos return NULL; 46742542f5fSchristos 46842542f5fSchristos sprintf(buf, "/dev/dri/card%d", (int)(st.st_rdev & 0x7f)); 46942542f5fSchristos if (stat(buf, &master) == 0 && 470fe8aea9eSmrg S_ISCHR(master.st_mode) && 47142542f5fSchristos (st.st_rdev & 0x7f) == master.st_rdev) 47242542f5fSchristos return strdup(buf); 47342542f5fSchristos 47442542f5fSchristos /* Fallback to iterating over the usual suspects */ 47542542f5fSchristos return drmGetDeviceNameFromFd(fd); 47642542f5fSchristos} 47742542f5fSchristos 47842542f5fSchristosstatic int is_render_node(int fd, struct stat *st) 47942542f5fSchristos{ 48042542f5fSchristos if (fstat(fd, st)) 481fe8aea9eSmrg return -1; 48242542f5fSchristos 48342542f5fSchristos if (!S_ISCHR(st->st_mode)) 484fe8aea9eSmrg return -1; 48542542f5fSchristos 48642542f5fSchristos return st->st_rdev & 0x80; 48742542f5fSchristos} 48842542f5fSchristos 48942542f5fSchristosstatic char *find_render_node(int fd) 49042542f5fSchristos{ 49142542f5fSchristos struct stat master, render; 49242542f5fSchristos char buf[128]; 493fe8aea9eSmrg int i; 49442542f5fSchristos 49542542f5fSchristos /* Are we a render-node ourselves? */ 49642542f5fSchristos if (is_render_node(fd, &master)) 49742542f5fSchristos return NULL; 49842542f5fSchristos 49942542f5fSchristos sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf)); 50042542f5fSchristos if (stat(buf, &render) == 0 && 501fe8aea9eSmrg S_ISCHR(render.st_mode) && 502fe8aea9eSmrg render.st_rdev == (master.st_rdev | 0x80)) 50342542f5fSchristos return strdup(buf); 504fe8aea9eSmrg 505fe8aea9eSmrg /* Misaligned card <-> renderD, do a full search */ 506fe8aea9eSmrg for (i = 0; i < 16; i++) { 507fe8aea9eSmrg sprintf(buf, "/dev/dri/renderD%d", i + 128); 508fe8aea9eSmrg if (stat(buf, &render) == 0 && 509fe8aea9eSmrg S_ISCHR(render.st_mode) && 510fe8aea9eSmrg render.st_rdev == (master.st_rdev | 0x80)) 511fe8aea9eSmrg return strdup(buf); 512fe8aea9eSmrg } 51342542f5fSchristos 51442542f5fSchristos return NULL; 51542542f5fSchristos} 51642542f5fSchristos 51742542f5fSchristos#if defined(ODEV_ATTRIB_PATH) 51842542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 51942542f5fSchristos{ 52042542f5fSchristos const char *path; 52142542f5fSchristos 52242542f5fSchristos if (dev == NULL) 52342542f5fSchristos return NULL; 52442542f5fSchristos 52542542f5fSchristos path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH); 52642542f5fSchristos if (path == NULL) 52742542f5fSchristos return NULL; 52842542f5fSchristos 52942542f5fSchristos return strdup(path); 53042542f5fSchristos} 53142542f5fSchristos 53242542f5fSchristos#else 53342542f5fSchristos 53442542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 53542542f5fSchristos{ 53642542f5fSchristos return NULL; 53742542f5fSchristos} 53842542f5fSchristos#endif 53942542f5fSchristos 54042542f5fSchristos 54142542f5fSchristos#if defined(ODEV_ATTRIB_FD) 54242542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 54342542f5fSchristos{ 54442542f5fSchristos if (dev == NULL) 54542542f5fSchristos return -1; 54642542f5fSchristos 54742542f5fSchristos return xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1); 54842542f5fSchristos} 54942542f5fSchristos 55042542f5fSchristos#else 55142542f5fSchristos 55242542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 55342542f5fSchristos{ 55442542f5fSchristos return -1; 55542542f5fSchristos} 55642542f5fSchristos#endif 55742542f5fSchristos 55842542f5fSchristosstatic int is_master(int fd) 55942542f5fSchristos{ 56042542f5fSchristos drmSetVersion sv; 56142542f5fSchristos 56242542f5fSchristos sv.drm_di_major = 1; 56342542f5fSchristos sv.drm_di_minor = 1; 56442542f5fSchristos sv.drm_dd_major = -1; 56542542f5fSchristos sv.drm_dd_minor = -1; 56642542f5fSchristos 56742542f5fSchristos return drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv) == 0; 56842542f5fSchristos} 56942542f5fSchristos 57003b705cfSriastradhint intel_open_device(int entity_num, 57103b705cfSriastradh const struct pci_device *pci, 57242542f5fSchristos struct xf86_platform_device *platform) 57303b705cfSriastradh{ 57403b705cfSriastradh struct intel_device *dev; 57542542f5fSchristos char *path; 57642542f5fSchristos int fd, master_count; 57703b705cfSriastradh 57803b705cfSriastradh if (intel_device_key == -1) 57903b705cfSriastradh intel_device_key = xf86AllocateEntityPrivateIndex(); 58003b705cfSriastradh if (intel_device_key == -1) 58103b705cfSriastradh return -1; 58203b705cfSriastradh 58303b705cfSriastradh dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 58403b705cfSriastradh if (dev) 58503b705cfSriastradh return dev->fd; 58603b705cfSriastradh 58742542f5fSchristos path = get_path(platform); 58803b705cfSriastradh 58942542f5fSchristos master_count = 1; /* DRM_MASTER is managed by Xserver */ 59042542f5fSchristos fd = get_fd(platform); 59142542f5fSchristos if (fd == -1) { 59242542f5fSchristos fd = __intel_open_device(pci, path); 59342542f5fSchristos if (fd == -1) 59442542f5fSchristos goto err_path; 59542542f5fSchristos 59642542f5fSchristos master_count = 0; 59742542f5fSchristos } 59842542f5fSchristos 59942542f5fSchristos if (path == NULL) { 60042542f5fSchristos path = find_master_node(fd); 60142542f5fSchristos if (path == NULL) 60242542f5fSchristos goto err_close; 60342542f5fSchristos } 60403b705cfSriastradh 60503b705cfSriastradh if (!__intel_check_device(fd)) 60603b705cfSriastradh goto err_close; 60703b705cfSriastradh 60803b705cfSriastradh dev = malloc(sizeof(*dev)); 60903b705cfSriastradh if (dev == NULL) 61003b705cfSriastradh goto err_close; 61103b705cfSriastradh 61203b705cfSriastradh /* If hosted under a system compositor, just pretend to be master */ 61342542f5fSchristos if (hosted()) 61442542f5fSchristos master_count++; 61542542f5fSchristos 61642542f5fSchristos /* Non-root user holding MASTER, don't let go */ 61742542f5fSchristos if (geteuid() && is_master(fd)) 61842542f5fSchristos master_count++; 61942542f5fSchristos 62013496ba1Ssnj if (pci) 62113496ba1Ssnj dev->device_id = pci->device_id; 62213496ba1Ssnj else 62313496ba1Ssnj dev->device_id = __intel_get_device_id(fd); 62413496ba1Ssnj 62513496ba1Ssnj dev->idx = entity_num; 62642542f5fSchristos dev->fd = fd; 62742542f5fSchristos dev->open_count = master_count; 62842542f5fSchristos dev->master_count = master_count; 62942542f5fSchristos dev->master_node = path; 63042542f5fSchristos dev->render_node = find_render_node(fd); 63142542f5fSchristos if (dev->render_node == NULL) 63242542f5fSchristos dev->render_node = dev->master_node; 63303b705cfSriastradh 63403b705cfSriastradh xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 63503b705cfSriastradh 63603b705cfSriastradh return fd; 63703b705cfSriastradh 63803b705cfSriastradherr_close: 63942542f5fSchristos if (master_count == 0) /* Don't close server-fds */ 64042542f5fSchristos close(fd); 64103b705cfSriastradherr_path: 64242542f5fSchristos free(path); 64303b705cfSriastradh return -1; 64403b705cfSriastradh} 64503b705cfSriastradh 646fe8aea9eSmrgvoid intel_close_device(int entity_num) 647fe8aea9eSmrg{ 648fe8aea9eSmrg struct intel_device *dev; 649fe8aea9eSmrg 650fe8aea9eSmrg if (intel_device_key == -1) 651fe8aea9eSmrg return; 652fe8aea9eSmrg 653fe8aea9eSmrg dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 654fe8aea9eSmrg xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = NULL; 655fe8aea9eSmrg if (!dev) 656fe8aea9eSmrg return; 657fe8aea9eSmrg 658fe8aea9eSmrg if (dev->master_count == 0) /* Don't close server-fds */ 659fe8aea9eSmrg close(dev->fd); 660fe8aea9eSmrg 661fe8aea9eSmrg if (dev->render_node != dev->master_node) 662fe8aea9eSmrg free(dev->render_node); 663fe8aea9eSmrg free(dev->master_node); 664fe8aea9eSmrg free(dev); 665fe8aea9eSmrg} 666fe8aea9eSmrg 66742542f5fSchristosint __intel_peek_fd(ScrnInfoPtr scrn) 66842542f5fSchristos{ 66942542f5fSchristos struct intel_device *dev; 67042542f5fSchristos 67142542f5fSchristos dev = intel_device(scrn); 67242542f5fSchristos assert(dev && dev->fd != -1); 67342542f5fSchristos 67442542f5fSchristos return dev->fd; 67542542f5fSchristos} 67642542f5fSchristos 67713496ba1Ssnjint intel_has_render_node(struct intel_device *dev) 67842542f5fSchristos{ 67942542f5fSchristos struct stat st; 68042542f5fSchristos 68142542f5fSchristos assert(dev && dev->fd != -1); 68242542f5fSchristos return is_render_node(dev->fd, &st); 68342542f5fSchristos} 68442542f5fSchristos 68513496ba1Ssnjstruct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd) 68603b705cfSriastradh{ 68703b705cfSriastradh struct intel_device *dev; 68803b705cfSriastradh int ret; 68903b705cfSriastradh 69003b705cfSriastradh dev = intel_device(scrn); 69113496ba1Ssnj if (dev == NULL) 69213496ba1Ssnj return NULL; 69313496ba1Ssnj 69413496ba1Ssnj assert(dev->fd != -1); 69503b705cfSriastradh 69603b705cfSriastradh if (dev->open_count++ == 0) { 69703b705cfSriastradh drmSetVersion sv; 69803b705cfSriastradh int retry = 2000; 69903b705cfSriastradh 70003b705cfSriastradh assert(!hosted()); 70103b705cfSriastradh 70203b705cfSriastradh /* Check that what we opened was a master or a 70303b705cfSriastradh * master-capable FD, by setting the version of the 70403b705cfSriastradh * interface we'll use to talk to it. 70503b705cfSriastradh */ 70603b705cfSriastradh do { 70703b705cfSriastradh sv.drm_di_major = 1; 70803b705cfSriastradh sv.drm_di_minor = 1; 70903b705cfSriastradh sv.drm_dd_major = -1; 71003b705cfSriastradh sv.drm_dd_minor = -1; 71103b705cfSriastradh ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 71203b705cfSriastradh if (ret == 0) 71303b705cfSriastradh break; 71403b705cfSriastradh 71503b705cfSriastradh usleep(1000); 71603b705cfSriastradh } while (--retry); 71703b705cfSriastradh if (ret != 0) { 71803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 71903b705cfSriastradh "[drm] failed to set drm interface version: %s [%d].\n", 72003b705cfSriastradh strerror(errno), errno); 72142542f5fSchristos dump_clients_info(scrn, dev->fd); 72203b705cfSriastradh dev->open_count--; 72313496ba1Ssnj return NULL; 72403b705cfSriastradh } 72503b705cfSriastradh } 72603b705cfSriastradh 72713496ba1Ssnj *fd = dev->fd; 72813496ba1Ssnj return dev; 72903b705cfSriastradh} 73003b705cfSriastradh 731fe8aea9eSmrgconst char *intel_get_master_name(struct intel_device *dev) 732fe8aea9eSmrg{ 733fe8aea9eSmrg assert(dev && dev->master_node); 734fe8aea9eSmrg return dev->master_node; 735fe8aea9eSmrg} 736fe8aea9eSmrg 73713496ba1Ssnjconst char *intel_get_client_name(struct intel_device *dev) 73842542f5fSchristos{ 73942542f5fSchristos assert(dev && dev->render_node); 74042542f5fSchristos return dev->render_node; 74142542f5fSchristos} 74242542f5fSchristos 74342542f5fSchristosstatic int authorise(struct intel_device *dev, int fd) 74442542f5fSchristos{ 74542542f5fSchristos struct stat st; 74642542f5fSchristos drm_magic_t magic; 74742542f5fSchristos 74842542f5fSchristos if (is_render_node(fd, &st)) /* restricted authority, do not elevate */ 74942542f5fSchristos return 1; 75042542f5fSchristos 75142542f5fSchristos return drmGetMagic(fd, &magic) == 0 && drmAuthMagic(dev->fd, magic) == 0; 75242542f5fSchristos} 75342542f5fSchristos 75413496ba1Ssnjint intel_get_client_fd(struct intel_device *dev) 75542542f5fSchristos{ 75642542f5fSchristos int fd = -1; 75742542f5fSchristos 75813496ba1Ssnj assert(dev && dev->fd != -1); 75942542f5fSchristos assert(dev->render_node); 76042542f5fSchristos 76142542f5fSchristos#ifdef O_CLOEXEC 76242542f5fSchristos fd = open(dev->render_node, O_RDWR | O_CLOEXEC); 76342542f5fSchristos#endif 76442542f5fSchristos if (fd < 0) 76542542f5fSchristos fd = fd_set_cloexec(open(dev->render_node, O_RDWR)); 76642542f5fSchristos if (fd < 0) 76742542f5fSchristos return -BadAlloc; 76842542f5fSchristos 76942542f5fSchristos if (!authorise(dev, fd)) { 77042542f5fSchristos close(fd); 77142542f5fSchristos return -BadMatch; 77242542f5fSchristos } 77342542f5fSchristos 77442542f5fSchristos assert(is_i915_gem(fd)); 77542542f5fSchristos 77642542f5fSchristos return fd; 77742542f5fSchristos} 77842542f5fSchristos 77913496ba1Ssnjint intel_get_device_id(struct intel_device *dev) 78003b705cfSriastradh{ 78142542f5fSchristos assert(dev && dev->fd != -1); 78213496ba1Ssnj return dev->device_id; 78303b705cfSriastradh} 78403b705cfSriastradh 78513496ba1Ssnjint intel_get_master(struct intel_device *dev) 78603b705cfSriastradh{ 78703b705cfSriastradh int ret; 78803b705cfSriastradh 78903b705cfSriastradh assert(dev && dev->fd != -1); 79003b705cfSriastradh 79103b705cfSriastradh ret = 0; 79203b705cfSriastradh if (dev->master_count++ == 0) { 79303b705cfSriastradh int retry = 2000; 79403b705cfSriastradh 79503b705cfSriastradh assert(!hosted()); 79603b705cfSriastradh do { 79703b705cfSriastradh ret = drmSetMaster(dev->fd); 79803b705cfSriastradh if (ret == 0) 79903b705cfSriastradh break; 80003b705cfSriastradh usleep(1000); 80103b705cfSriastradh } while (--retry); 80203b705cfSriastradh } 80303b705cfSriastradh 80403b705cfSriastradh return ret; 80503b705cfSriastradh} 80603b705cfSriastradh 80713496ba1Ssnjint intel_put_master(struct intel_device *dev) 80803b705cfSriastradh{ 80903b705cfSriastradh int ret; 81003b705cfSriastradh 81103b705cfSriastradh assert(dev && dev->fd != -1); 81203b705cfSriastradh 81303b705cfSriastradh ret = 0; 81403b705cfSriastradh assert(dev->master_count); 81503b705cfSriastradh if (--dev->master_count == 0) { 81603b705cfSriastradh assert(!hosted()); 81703b705cfSriastradh assert(drmSetMaster(dev->fd) == 0); 81803b705cfSriastradh ret = drmDropMaster(dev->fd); 81903b705cfSriastradh } 82003b705cfSriastradh 82103b705cfSriastradh return ret; 82203b705cfSriastradh} 82303b705cfSriastradh 82413496ba1Ssnjvoid intel_put_device(struct intel_device *dev) 82503b705cfSriastradh{ 82603b705cfSriastradh assert(dev && dev->fd != -1); 82703b705cfSriastradh 82803b705cfSriastradh assert(dev->open_count); 82903b705cfSriastradh if (--dev->open_count) 83003b705cfSriastradh return; 83103b705cfSriastradh 83203b705cfSriastradh assert(!hosted()); 83313496ba1Ssnj xf86GetEntityPrivate(dev->idx, intel_device_key)->ptr = NULL; 83403b705cfSriastradh 83503b705cfSriastradh drmClose(dev->fd); 83642542f5fSchristos if (dev->render_node != dev->master_node) 83742542f5fSchristos free(dev->render_node); 83842542f5fSchristos free(dev->master_node); 83903b705cfSriastradh free(dev); 84003b705cfSriastradh} 841