intel_device.c revision 42542f5f
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 4103b705cfSriastradh#include <pciaccess.h> 4242542f5fSchristos 4342542f5fSchristos#include <xorg-server.h> 4403b705cfSriastradh#include <xf86.h> 4503b705cfSriastradh#include <xf86drm.h> 4603b705cfSriastradh#include <xf86drmMode.h> 4703b705cfSriastradh#include <xf86_OSproc.h> 4803b705cfSriastradh#include <i915_drm.h> 4903b705cfSriastradh 5042542f5fSchristos#ifdef XSERVER_PLATFORM_BUS 5142542f5fSchristos#include <xf86platformBus.h> 5242542f5fSchristos#endif 5342542f5fSchristos 5442542f5fSchristos#ifdef HAVE_VALGRIND 5542542f5fSchristos#include <valgrind.h> 5642542f5fSchristos#include <memcheck.h> 5742542f5fSchristos#define VG(x) x 5842542f5fSchristos#else 5942542f5fSchristos#define VG(x) 6042542f5fSchristos#endif 6142542f5fSchristos 6242542f5fSchristos#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) 6342542f5fSchristos 6403b705cfSriastradh#include "intel_driver.h" 6542542f5fSchristos#include "fd.h" 6603b705cfSriastradh 6703b705cfSriastradhstruct intel_device { 6842542f5fSchristos char *master_node; 6942542f5fSchristos char *render_node; 7003b705cfSriastradh int fd; 7103b705cfSriastradh int open_count; 7203b705cfSriastradh int master_count; 7303b705cfSriastradh}; 7403b705cfSriastradh 7503b705cfSriastradhstatic int intel_device_key = -1; 7603b705cfSriastradh 7742542f5fSchristosstatic int dump_file(ScrnInfoPtr scrn, const char *path) 7842542f5fSchristos{ 7942542f5fSchristos FILE *file; 8042542f5fSchristos size_t len = 0; 8142542f5fSchristos char *line = NULL; 8242542f5fSchristos 8342542f5fSchristos file = fopen(path, "r"); 8442542f5fSchristos if (file == NULL) 8542542f5fSchristos return 0; 8642542f5fSchristos 8742542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] Contents of '%s':\n", path); 8842542f5fSchristos while (getline(&line, &len, file) != -1) 8942542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] %s", line); 9042542f5fSchristos 9142542f5fSchristos free(line); 9242542f5fSchristos fclose(file); 9342542f5fSchristos return 1; 9442542f5fSchristos} 9542542f5fSchristos 9642542f5fSchristosstatic int __find_debugfs(void) 9742542f5fSchristos{ 9842542f5fSchristos int i; 9942542f5fSchristos 10042542f5fSchristos for (i = 0; i < DRM_MAX_MINOR; i++) { 10142542f5fSchristos char path[80]; 10242542f5fSchristos 10342542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 10442542f5fSchristos if (access(path, R_OK) == 0) 10542542f5fSchristos return i; 10642542f5fSchristos 10742542f5fSchristos sprintf(path, "/debug/dri/%d/i915_wedged", i); 10842542f5fSchristos if (access(path, R_OK) == 0) 10942542f5fSchristos return i; 11042542f5fSchristos } 11142542f5fSchristos 11242542f5fSchristos return -1; 11342542f5fSchristos} 11442542f5fSchristos 11542542f5fSchristosstatic int drm_get_minor(int fd) 11642542f5fSchristos{ 11742542f5fSchristos struct stat st; 11842542f5fSchristos 11942542f5fSchristos if (fstat(fd, &st)) 12042542f5fSchristos return __find_debugfs(); 12142542f5fSchristos 12242542f5fSchristos if (!S_ISCHR(st.st_mode)) 12342542f5fSchristos return __find_debugfs(); 12442542f5fSchristos 12542542f5fSchristos return st.st_rdev & 0x63; 12642542f5fSchristos} 12742542f5fSchristos 12842542f5fSchristos#if __linux__ 12942542f5fSchristos#include <sys/mount.h> 13042542f5fSchristos 13142542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) 13242542f5fSchristos{ 13342542f5fSchristos char path[80]; 13442542f5fSchristos int minor; 13542542f5fSchristos 13642542f5fSchristos minor = drm_get_minor(fd); 13742542f5fSchristos if (minor < 0) 13842542f5fSchristos return; 13942542f5fSchristos 14042542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 14142542f5fSchristos if (dump_file(scrn, path)) 14242542f5fSchristos return; 14342542f5fSchristos 14442542f5fSchristos sprintf(path, "/debug/dri/%d/%s", minor, name); 14542542f5fSchristos if (dump_file(scrn, path)) 14642542f5fSchristos return; 14742542f5fSchristos 14842542f5fSchristos if (mount("X-debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0) { 14942542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 15042542f5fSchristos dump_file(scrn, path); 15142542f5fSchristos umount("X-debug"); 15242542f5fSchristos return; 15342542f5fSchristos } 15442542f5fSchristos} 15542542f5fSchristos#else 15642542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) { } 15742542f5fSchristos#endif 15842542f5fSchristos 15942542f5fSchristosstatic void dump_clients_info(ScrnInfoPtr scrn, int fd) 16042542f5fSchristos{ 16142542f5fSchristos dump_debugfs(scrn, fd, "clients"); 16242542f5fSchristos} 16342542f5fSchristos 16442542f5fSchristosstatic int __intel_get_device_id(int fd) 16542542f5fSchristos{ 16642542f5fSchristos struct drm_i915_getparam gp; 16742542f5fSchristos int devid = 0; 16842542f5fSchristos 16942542f5fSchristos VG_CLEAR(gp); 17042542f5fSchristos gp.param = I915_PARAM_CHIPSET_ID; 17142542f5fSchristos gp.value = &devid; 17242542f5fSchristos 17342542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 17442542f5fSchristos return 0; 17542542f5fSchristos 17642542f5fSchristos return devid; 17742542f5fSchristos} 17842542f5fSchristos 17942542f5fSchristosint intel_entity_get_devid(int idx) 18042542f5fSchristos{ 18142542f5fSchristos struct intel_device *dev; 18242542f5fSchristos 18342542f5fSchristos dev = xf86GetEntityPrivate(idx, intel_device_key)->ptr; 18442542f5fSchristos if (dev == NULL) 18542542f5fSchristos return 0; 18642542f5fSchristos 18742542f5fSchristos return __intel_get_device_id(dev->fd); 18842542f5fSchristos} 18942542f5fSchristos 19003b705cfSriastradhstatic inline struct intel_device *intel_device(ScrnInfoPtr scrn) 19103b705cfSriastradh{ 19203b705cfSriastradh if (scrn->entityList == NULL) 19303b705cfSriastradh return NULL; 19403b705cfSriastradh 19503b705cfSriastradh return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 19603b705cfSriastradh} 19703b705cfSriastradh 19803b705cfSriastradhstatic inline void intel_set_device(ScrnInfoPtr scrn, struct intel_device *dev) 19903b705cfSriastradh{ 20003b705cfSriastradh xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr = dev; 20103b705cfSriastradh} 20203b705cfSriastradh 20342542f5fSchristosstatic int is_i915_device(int fd) 20403b705cfSriastradh{ 20503b705cfSriastradh drm_version_t version; 20603b705cfSriastradh char name[5] = ""; 20703b705cfSriastradh 20803b705cfSriastradh memset(&version, 0, sizeof(version)); 20903b705cfSriastradh version.name_len = 4; 21003b705cfSriastradh version.name = name; 21103b705cfSriastradh 21203b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 21342542f5fSchristos return 0; 21403b705cfSriastradh 21503b705cfSriastradh return strcmp("i915", name) == 0; 21603b705cfSriastradh} 21703b705cfSriastradh 21842542f5fSchristosstatic int is_i915_gem(int fd) 21903b705cfSriastradh{ 22042542f5fSchristos int ret = is_i915_device(fd); 22103b705cfSriastradh 22203b705cfSriastradh if (ret) { 22303b705cfSriastradh struct drm_i915_getparam gp; 22442542f5fSchristos 22542542f5fSchristos VG_CLEAR(gp); 22603b705cfSriastradh gp.param = I915_PARAM_HAS_GEM; 22703b705cfSriastradh gp.value = &ret; 22842542f5fSchristos 22903b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 23042542f5fSchristos ret = 0; 23103b705cfSriastradh } 23242542f5fSchristos 23342542f5fSchristos return ret; 23442542f5fSchristos} 23542542f5fSchristos 23642542f5fSchristosstatic int __intel_check_device(int fd) 23742542f5fSchristos{ 23842542f5fSchristos int ret; 23942542f5fSchristos 24042542f5fSchristos /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 24142542f5fSchristos ret = is_i915_gem(fd); 24203b705cfSriastradh if (ret && !hosted()) { 24303b705cfSriastradh struct drm_mode_card_res res; 24403b705cfSriastradh 24503b705cfSriastradh memset(&res, 0, sizeof(res)); 24603b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 24742542f5fSchristos ret = 0; 24803b705cfSriastradh } 24903b705cfSriastradh 25003b705cfSriastradh return ret; 25103b705cfSriastradh} 25203b705cfSriastradh 25342542f5fSchristosstatic int open_cloexec(const char *path) 25403b705cfSriastradh{ 25542542f5fSchristos struct stat st; 25642542f5fSchristos int loop = 1000; 25742542f5fSchristos int fd; 25803b705cfSriastradh 25942542f5fSchristos /* No file? Assume the driver is loading slowly */ 26042542f5fSchristos while (stat(path, &st) == -1 && errno == ENOENT && --loop) 26142542f5fSchristos usleep(50000); 26242542f5fSchristos 26342542f5fSchristos if (loop != 1000) 26442542f5fSchristos ErrorF("intel: waited %d ms for '%s' to appear\n", 26542542f5fSchristos (1000 - loop) * 50, path); 26642542f5fSchristos 26742542f5fSchristos fd = -1; 26842542f5fSchristos#ifdef O_CLOEXEC 26942542f5fSchristos fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC); 27042542f5fSchristos#endif 27103b705cfSriastradh if (fd == -1) 27242542f5fSchristos fd = fd_set_cloexec(open(path, O_RDWR | O_NONBLOCK)); 27303b705cfSriastradh 27442542f5fSchristos return fd; 27542542f5fSchristos} 27642542f5fSchristos 27742542f5fSchristos#ifdef __linux__ 27842542f5fSchristosstatic int __intel_open_device__major_minor(int _major, int _minor) 27942542f5fSchristos{ 28042542f5fSchristos char path[256]; 28142542f5fSchristos DIR *dir; 28242542f5fSchristos struct dirent *de; 28342542f5fSchristos int base, fd = -1; 28442542f5fSchristos 28542542f5fSchristos base = sprintf(path, "/dev/dri/"); 28642542f5fSchristos 28742542f5fSchristos dir = opendir(path); 28842542f5fSchristos if (dir == NULL) 28942542f5fSchristos return -1; 29042542f5fSchristos 29142542f5fSchristos while ((de = readdir(dir)) != NULL) { 29242542f5fSchristos struct stat st; 29342542f5fSchristos 29442542f5fSchristos if (*de->d_name == '.') 29542542f5fSchristos continue; 29642542f5fSchristos 29742542f5fSchristos sprintf(path + base, "%s", de->d_name); 29842542f5fSchristos if (stat(path, &st) == 0 && 29942542f5fSchristos major(st.st_rdev) == _major && 30042542f5fSchristos minor(st.st_rdev) == _minor) { 30142542f5fSchristos fd = open_cloexec(path); 30242542f5fSchristos break; 30342542f5fSchristos } 30403b705cfSriastradh } 30542542f5fSchristos 30642542f5fSchristos closedir(dir); 30703b705cfSriastradh 30803b705cfSriastradh return fd; 30903b705cfSriastradh} 31003b705cfSriastradh 31142542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) 31203b705cfSriastradh{ 31342542f5fSchristos struct stat st; 31442542f5fSchristos char path[256]; 31542542f5fSchristos DIR *dir; 31642542f5fSchristos struct dirent *de; 31742542f5fSchristos int base; 31803b705cfSriastradh int fd; 31903b705cfSriastradh 32042542f5fSchristos /* Look up the major:minor for the drm device through sysfs. 32142542f5fSchristos * First we need to check that sysfs is available, then 32242542f5fSchristos * check that we have loaded our driver. When we are happy 32342542f5fSchristos * that our KMS module is loaded, we can then search for our 32442542f5fSchristos * device node. We make the assumption that it uses the same 32542542f5fSchristos * name, but after that we read the major:minor assigned to us 32642542f5fSchristos * and search for a matching entry in /dev. 32742542f5fSchristos */ 32842542f5fSchristos 32942542f5fSchristos base = sprintf(path, 33042542f5fSchristos "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 33142542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 33242542f5fSchristos if (stat(path, &st)) 33342542f5fSchristos return -1; 33403b705cfSriastradh 33542542f5fSchristos sprintf(path + base, "drm"); 33642542f5fSchristos dir = opendir(path); 33742542f5fSchristos if (dir == NULL) { 33842542f5fSchristos int loop = 0; 33903b705cfSriastradh 34042542f5fSchristos sprintf(path + base, "driver"); 34142542f5fSchristos if (stat(path, &st)) { 34203b705cfSriastradh if (xf86LoadKernelModule("i915")) 34303b705cfSriastradh return -1; 34403b705cfSriastradh (void)xf86LoadKernelModule("fbcon"); 34503b705cfSriastradh } 34603b705cfSriastradh 34742542f5fSchristos sprintf(path + base, "drm"); 34842542f5fSchristos while ((dir = opendir(path)) == NULL && loop++ < 100) 34942542f5fSchristos usleep(20000); 35042542f5fSchristos 35142542f5fSchristos ErrorF("intel: waited %d ms for i915.ko driver to load\n", loop * 20000 / 1000); 35242542f5fSchristos 35342542f5fSchristos if (dir == NULL) 35442542f5fSchristos return -1; 35542542f5fSchristos } 35642542f5fSchristos 35742542f5fSchristos fd = -1; 35842542f5fSchristos while ((de = readdir(dir)) != NULL) { 35942542f5fSchristos if (*de->d_name == '.') 36042542f5fSchristos continue; 36142542f5fSchristos 36242542f5fSchristos if (strncmp(de->d_name, "card", 4) == 0) { 36342542f5fSchristos sprintf(path + base + 4, "/dev/dri/%s", de->d_name); 36442542f5fSchristos fd = open_cloexec(path + base + 4); 36542542f5fSchristos if (fd != -1) 36642542f5fSchristos break; 36742542f5fSchristos 36842542f5fSchristos sprintf(path + base + 3, "/%s/dev", de->d_name); 36942542f5fSchristos fd = open(path, O_RDONLY); 37042542f5fSchristos if (fd == -1) 37142542f5fSchristos break; 37242542f5fSchristos 37342542f5fSchristos base = read(fd, path, sizeof(path) - 1); 37442542f5fSchristos close(fd); 37542542f5fSchristos 37642542f5fSchristos fd = -1; 37742542f5fSchristos if (base > 0) { 37842542f5fSchristos int major, minor; 37942542f5fSchristos path[base] = '\0'; 38042542f5fSchristos if (sscanf(path, "%d:%d", &major, &minor) == 2) 38142542f5fSchristos fd = __intel_open_device__major_minor(major, minor); 38203b705cfSriastradh } 38342542f5fSchristos break; 38403b705cfSriastradh } 38542542f5fSchristos } 38642542f5fSchristos closedir(dir); 38742542f5fSchristos 38842542f5fSchristos return fd; 38942542f5fSchristos} 39003b705cfSriastradh#else 39142542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) { return -1; } 39203b705cfSriastradh#endif 39342542f5fSchristos 39442542f5fSchristosstatic int __intel_open_device__legacy(const struct pci_device *pci) 39542542f5fSchristos{ 39642542f5fSchristos char id[20]; 39742542f5fSchristos int ret; 39842542f5fSchristos 39942542f5fSchristos snprintf(id, sizeof(id), 40042542f5fSchristos "pci:%04x:%02x:%02x.%d", 40142542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 40242542f5fSchristos 40342542f5fSchristos ret = drmCheckModesettingSupported(id); 40442542f5fSchristos if (ret) { 40542542f5fSchristos if (xf86LoadKernelModule("i915")) 40642542f5fSchristos ret = drmCheckModesettingSupported(id); 40742542f5fSchristos if (ret) 40842542f5fSchristos return -1; 40942542f5fSchristos /* Be nice to the user and load fbcon too */ 41042542f5fSchristos (void)xf86LoadKernelModule("fbcon"); 41103b705cfSriastradh } 41203b705cfSriastradh 41342542f5fSchristos return fd_set_nonblock(drmOpen(NULL, id)); 41442542f5fSchristos} 41542542f5fSchristos 41642542f5fSchristosstatic int __intel_open_device(const struct pci_device *pci, const char *path) 41742542f5fSchristos{ 41842542f5fSchristos int fd; 41942542f5fSchristos 42042542f5fSchristos if (path == NULL) { 42142542f5fSchristos if (pci == NULL) 42242542f5fSchristos return -1; 42342542f5fSchristos 42442542f5fSchristos fd = __intel_open_device__pci(pci); 42542542f5fSchristos if (fd == -1) 42642542f5fSchristos fd = __intel_open_device__legacy(pci); 42742542f5fSchristos } else 42842542f5fSchristos fd = open_cloexec(path); 42942542f5fSchristos 43003b705cfSriastradh return fd; 43103b705cfSriastradh} 43203b705cfSriastradh 43342542f5fSchristosstatic char *find_master_node(int fd) 43442542f5fSchristos{ 43542542f5fSchristos struct stat st, master; 43642542f5fSchristos char buf[128]; 43742542f5fSchristos 43842542f5fSchristos if (fstat(fd, &st)) 43942542f5fSchristos return NULL; 44042542f5fSchristos 44142542f5fSchristos if (!S_ISCHR(st.st_mode)) 44242542f5fSchristos return NULL; 44342542f5fSchristos 44442542f5fSchristos sprintf(buf, "/dev/dri/card%d", (int)(st.st_rdev & 0x7f)); 44542542f5fSchristos if (stat(buf, &master) == 0 && 44642542f5fSchristos st.st_mode == master.st_mode && 44742542f5fSchristos (st.st_rdev & 0x7f) == master.st_rdev) 44842542f5fSchristos return strdup(buf); 44942542f5fSchristos 45042542f5fSchristos /* Fallback to iterating over the usual suspects */ 45142542f5fSchristos return drmGetDeviceNameFromFd(fd); 45242542f5fSchristos} 45342542f5fSchristos 45442542f5fSchristosstatic int is_render_node(int fd, struct stat *st) 45542542f5fSchristos{ 45642542f5fSchristos if (fstat(fd, st)) 45742542f5fSchristos return 0; 45842542f5fSchristos 45942542f5fSchristos if (!S_ISCHR(st->st_mode)) 46042542f5fSchristos return 0; 46142542f5fSchristos 46242542f5fSchristos return st->st_rdev & 0x80; 46342542f5fSchristos} 46442542f5fSchristos 46542542f5fSchristosstatic char *find_render_node(int fd) 46642542f5fSchristos{ 46742542f5fSchristos#if defined(USE_RENDERNODE) 46842542f5fSchristos struct stat master, render; 46942542f5fSchristos char buf[128]; 47042542f5fSchristos 47142542f5fSchristos /* Are we a render-node ourselves? */ 47242542f5fSchristos if (is_render_node(fd, &master)) 47342542f5fSchristos return NULL; 47442542f5fSchristos 47542542f5fSchristos sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf)); 47642542f5fSchristos if (stat(buf, &render) == 0 && 47742542f5fSchristos master.st_mode == render.st_mode && 47842542f5fSchristos render.st_rdev == ((master.st_rdev | 0x80) & 0xbf)) 47942542f5fSchristos return strdup(buf); 48042542f5fSchristos#endif 48142542f5fSchristos 48242542f5fSchristos return NULL; 48342542f5fSchristos} 48442542f5fSchristos 48542542f5fSchristos#if defined(ODEV_ATTRIB_PATH) 48642542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 48742542f5fSchristos{ 48842542f5fSchristos const char *path; 48942542f5fSchristos 49042542f5fSchristos if (dev == NULL) 49142542f5fSchristos return NULL; 49242542f5fSchristos 49342542f5fSchristos path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH); 49442542f5fSchristos if (path == NULL) 49542542f5fSchristos return NULL; 49642542f5fSchristos 49742542f5fSchristos return strdup(path); 49842542f5fSchristos} 49942542f5fSchristos 50042542f5fSchristos#else 50142542f5fSchristos 50242542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 50342542f5fSchristos{ 50442542f5fSchristos return NULL; 50542542f5fSchristos} 50642542f5fSchristos#endif 50742542f5fSchristos 50842542f5fSchristos 50942542f5fSchristos#if defined(ODEV_ATTRIB_FD) 51042542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 51142542f5fSchristos{ 51242542f5fSchristos if (dev == NULL) 51342542f5fSchristos return -1; 51442542f5fSchristos 51542542f5fSchristos return xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1); 51642542f5fSchristos} 51742542f5fSchristos 51842542f5fSchristos#else 51942542f5fSchristos 52042542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 52142542f5fSchristos{ 52242542f5fSchristos return -1; 52342542f5fSchristos} 52442542f5fSchristos#endif 52542542f5fSchristos 52642542f5fSchristosstatic int is_master(int fd) 52742542f5fSchristos{ 52842542f5fSchristos drmSetVersion sv; 52942542f5fSchristos 53042542f5fSchristos sv.drm_di_major = 1; 53142542f5fSchristos sv.drm_di_minor = 1; 53242542f5fSchristos sv.drm_dd_major = -1; 53342542f5fSchristos sv.drm_dd_minor = -1; 53442542f5fSchristos 53542542f5fSchristos return drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv) == 0; 53642542f5fSchristos} 53742542f5fSchristos 53803b705cfSriastradhint intel_open_device(int entity_num, 53903b705cfSriastradh const struct pci_device *pci, 54042542f5fSchristos struct xf86_platform_device *platform) 54103b705cfSriastradh{ 54203b705cfSriastradh struct intel_device *dev; 54342542f5fSchristos char *path; 54442542f5fSchristos int fd, master_count; 54503b705cfSriastradh 54603b705cfSriastradh if (intel_device_key == -1) 54703b705cfSriastradh intel_device_key = xf86AllocateEntityPrivateIndex(); 54803b705cfSriastradh if (intel_device_key == -1) 54903b705cfSriastradh return -1; 55003b705cfSriastradh 55103b705cfSriastradh dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 55203b705cfSriastradh if (dev) 55303b705cfSriastradh return dev->fd; 55403b705cfSriastradh 55542542f5fSchristos path = get_path(platform); 55603b705cfSriastradh 55742542f5fSchristos master_count = 1; /* DRM_MASTER is managed by Xserver */ 55842542f5fSchristos fd = get_fd(platform); 55942542f5fSchristos if (fd == -1) { 56042542f5fSchristos fd = __intel_open_device(pci, path); 56142542f5fSchristos if (fd == -1) 56242542f5fSchristos goto err_path; 56342542f5fSchristos 56442542f5fSchristos master_count = 0; 56542542f5fSchristos } 56642542f5fSchristos 56742542f5fSchristos if (path == NULL) { 56842542f5fSchristos path = find_master_node(fd); 56942542f5fSchristos if (path == NULL) 57042542f5fSchristos goto err_close; 57142542f5fSchristos } 57203b705cfSriastradh 57303b705cfSriastradh if (!__intel_check_device(fd)) 57403b705cfSriastradh goto err_close; 57503b705cfSriastradh 57603b705cfSriastradh dev = malloc(sizeof(*dev)); 57703b705cfSriastradh if (dev == NULL) 57803b705cfSriastradh goto err_close; 57903b705cfSriastradh 58003b705cfSriastradh /* If hosted under a system compositor, just pretend to be master */ 58142542f5fSchristos if (hosted()) 58242542f5fSchristos master_count++; 58342542f5fSchristos 58442542f5fSchristos /* Non-root user holding MASTER, don't let go */ 58542542f5fSchristos if (geteuid() && is_master(fd)) 58642542f5fSchristos master_count++; 58742542f5fSchristos 58842542f5fSchristos dev->fd = fd; 58942542f5fSchristos dev->open_count = master_count; 59042542f5fSchristos dev->master_count = master_count; 59142542f5fSchristos dev->master_node = path; 59242542f5fSchristos dev->render_node = find_render_node(fd); 59342542f5fSchristos if (dev->render_node == NULL) 59442542f5fSchristos dev->render_node = dev->master_node; 59503b705cfSriastradh 59603b705cfSriastradh xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 59703b705cfSriastradh 59803b705cfSriastradh return fd; 59903b705cfSriastradh 60003b705cfSriastradherr_close: 60142542f5fSchristos if (master_count == 0) /* Don't close server-fds */ 60242542f5fSchristos close(fd); 60303b705cfSriastradherr_path: 60442542f5fSchristos free(path); 60503b705cfSriastradh return -1; 60603b705cfSriastradh} 60703b705cfSriastradh 60842542f5fSchristosint __intel_peek_fd(ScrnInfoPtr scrn) 60942542f5fSchristos{ 61042542f5fSchristos struct intel_device *dev; 61142542f5fSchristos 61242542f5fSchristos dev = intel_device(scrn); 61342542f5fSchristos assert(dev && dev->fd != -1); 61442542f5fSchristos 61542542f5fSchristos return dev->fd; 61642542f5fSchristos} 61742542f5fSchristos 61842542f5fSchristosint intel_has_render_node(ScrnInfoPtr scrn) 61942542f5fSchristos{ 62042542f5fSchristos struct intel_device *dev; 62142542f5fSchristos struct stat st; 62242542f5fSchristos 62342542f5fSchristos dev = intel_device(scrn); 62442542f5fSchristos assert(dev && dev->fd != -1); 62542542f5fSchristos 62642542f5fSchristos return is_render_node(dev->fd, &st); 62742542f5fSchristos} 62842542f5fSchristos 62903b705cfSriastradhint intel_get_device(ScrnInfoPtr scrn) 63003b705cfSriastradh{ 63103b705cfSriastradh struct intel_device *dev; 63203b705cfSriastradh int ret; 63303b705cfSriastradh 63403b705cfSriastradh dev = intel_device(scrn); 63503b705cfSriastradh assert(dev && dev->fd != -1); 63603b705cfSriastradh 63703b705cfSriastradh if (dev->open_count++ == 0) { 63803b705cfSriastradh drmSetVersion sv; 63903b705cfSriastradh int retry = 2000; 64003b705cfSriastradh 64103b705cfSriastradh assert(!hosted()); 64203b705cfSriastradh 64303b705cfSriastradh /* Check that what we opened was a master or a 64403b705cfSriastradh * master-capable FD, by setting the version of the 64503b705cfSriastradh * interface we'll use to talk to it. 64603b705cfSriastradh */ 64703b705cfSriastradh do { 64803b705cfSriastradh sv.drm_di_major = 1; 64903b705cfSriastradh sv.drm_di_minor = 1; 65003b705cfSriastradh sv.drm_dd_major = -1; 65103b705cfSriastradh sv.drm_dd_minor = -1; 65203b705cfSriastradh ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 65303b705cfSriastradh if (ret == 0) 65403b705cfSriastradh break; 65503b705cfSriastradh 65603b705cfSriastradh usleep(1000); 65703b705cfSriastradh } while (--retry); 65803b705cfSriastradh if (ret != 0) { 65903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 66003b705cfSriastradh "[drm] failed to set drm interface version: %s [%d].\n", 66103b705cfSriastradh strerror(errno), errno); 66242542f5fSchristos dump_clients_info(scrn, dev->fd); 66303b705cfSriastradh dev->open_count--; 66403b705cfSriastradh return -1; 66503b705cfSriastradh } 66603b705cfSriastradh } 66703b705cfSriastradh 66803b705cfSriastradh return dev->fd; 66903b705cfSriastradh} 67003b705cfSriastradh 67142542f5fSchristosconst char *intel_get_client_name(ScrnInfoPtr scrn) 67242542f5fSchristos{ 67342542f5fSchristos struct intel_device *dev = intel_device(scrn); 67442542f5fSchristos assert(dev && dev->render_node); 67542542f5fSchristos return dev->render_node; 67642542f5fSchristos} 67742542f5fSchristos 67842542f5fSchristosstatic int authorise(struct intel_device *dev, int fd) 67942542f5fSchristos{ 68042542f5fSchristos struct stat st; 68142542f5fSchristos drm_magic_t magic; 68242542f5fSchristos 68342542f5fSchristos if (is_render_node(fd, &st)) /* restricted authority, do not elevate */ 68442542f5fSchristos return 1; 68542542f5fSchristos 68642542f5fSchristos return drmGetMagic(fd, &magic) == 0 && drmAuthMagic(dev->fd, magic) == 0; 68742542f5fSchristos} 68842542f5fSchristos 68942542f5fSchristosint intel_get_client_fd(ScrnInfoPtr scrn) 69042542f5fSchristos{ 69142542f5fSchristos struct intel_device *dev; 69242542f5fSchristos int fd = -1; 69342542f5fSchristos 69442542f5fSchristos dev = intel_device(scrn); 69542542f5fSchristos assert(dev); 69642542f5fSchristos assert(dev->fd != -1); 69742542f5fSchristos assert(dev->render_node); 69842542f5fSchristos 69942542f5fSchristos#ifdef O_CLOEXEC 70042542f5fSchristos fd = open(dev->render_node, O_RDWR | O_CLOEXEC); 70142542f5fSchristos#endif 70242542f5fSchristos if (fd < 0) 70342542f5fSchristos fd = fd_set_cloexec(open(dev->render_node, O_RDWR)); 70442542f5fSchristos if (fd < 0) 70542542f5fSchristos return -BadAlloc; 70642542f5fSchristos 70742542f5fSchristos if (!authorise(dev, fd)) { 70842542f5fSchristos close(fd); 70942542f5fSchristos return -BadMatch; 71042542f5fSchristos } 71142542f5fSchristos 71242542f5fSchristos assert(is_i915_gem(fd)); 71342542f5fSchristos 71442542f5fSchristos return fd; 71542542f5fSchristos} 71642542f5fSchristos 71742542f5fSchristosint intel_get_device_id(ScrnInfoPtr scrn) 71803b705cfSriastradh{ 71903b705cfSriastradh struct intel_device *dev = intel_device(scrn); 72042542f5fSchristos assert(dev && dev->fd != -1); 72142542f5fSchristos return __intel_get_device_id(dev->fd); 72203b705cfSriastradh} 72303b705cfSriastradh 72403b705cfSriastradhint intel_get_master(ScrnInfoPtr scrn) 72503b705cfSriastradh{ 72603b705cfSriastradh struct intel_device *dev = intel_device(scrn); 72703b705cfSriastradh int ret; 72803b705cfSriastradh 72903b705cfSriastradh assert(dev && dev->fd != -1); 73003b705cfSriastradh 73103b705cfSriastradh ret = 0; 73203b705cfSriastradh if (dev->master_count++ == 0) { 73303b705cfSriastradh int retry = 2000; 73403b705cfSriastradh 73503b705cfSriastradh assert(!hosted()); 73603b705cfSriastradh do { 73703b705cfSriastradh ret = drmSetMaster(dev->fd); 73803b705cfSriastradh if (ret == 0) 73903b705cfSriastradh break; 74003b705cfSriastradh usleep(1000); 74103b705cfSriastradh } while (--retry); 74203b705cfSriastradh } 74303b705cfSriastradh 74403b705cfSriastradh return ret; 74503b705cfSriastradh} 74603b705cfSriastradh 74703b705cfSriastradhint intel_put_master(ScrnInfoPtr scrn) 74803b705cfSriastradh{ 74903b705cfSriastradh struct intel_device *dev = intel_device(scrn); 75003b705cfSriastradh int ret; 75103b705cfSriastradh 75203b705cfSriastradh assert(dev && dev->fd != -1); 75303b705cfSriastradh 75403b705cfSriastradh ret = 0; 75503b705cfSriastradh assert(dev->master_count); 75603b705cfSriastradh if (--dev->master_count == 0) { 75703b705cfSriastradh assert(!hosted()); 75803b705cfSriastradh assert(drmSetMaster(dev->fd) == 0); 75903b705cfSriastradh ret = drmDropMaster(dev->fd); 76003b705cfSriastradh } 76103b705cfSriastradh 76203b705cfSriastradh return ret; 76303b705cfSriastradh} 76403b705cfSriastradh 76503b705cfSriastradhvoid intel_put_device(ScrnInfoPtr scrn) 76603b705cfSriastradh{ 76703b705cfSriastradh struct intel_device *dev = intel_device(scrn); 76803b705cfSriastradh 76903b705cfSriastradh assert(dev && dev->fd != -1); 77003b705cfSriastradh 77103b705cfSriastradh assert(dev->open_count); 77203b705cfSriastradh if (--dev->open_count) 77303b705cfSriastradh return; 77403b705cfSriastradh 77503b705cfSriastradh assert(!hosted()); 77603b705cfSriastradh intel_set_device(scrn, NULL); 77703b705cfSriastradh 77803b705cfSriastradh drmClose(dev->fd); 77942542f5fSchristos if (dev->render_node != dev->master_node) 78042542f5fSchristos free(dev->render_node); 78142542f5fSchristos free(dev->master_node); 78203b705cfSriastradh free(dev); 78303b705cfSriastradh} 784