intel_device.c revision 13496ba1
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 { 6813496ba1Ssnj int idx; 6942542f5fSchristos char *master_node; 7042542f5fSchristos char *render_node; 7103b705cfSriastradh int fd; 7213496ba1Ssnj int device_id; 7303b705cfSriastradh int open_count; 7403b705cfSriastradh int master_count; 7503b705cfSriastradh}; 7603b705cfSriastradh 7703b705cfSriastradhstatic int intel_device_key = -1; 7803b705cfSriastradh 7942542f5fSchristosstatic int dump_file(ScrnInfoPtr scrn, const char *path) 8042542f5fSchristos{ 8142542f5fSchristos FILE *file; 8242542f5fSchristos size_t len = 0; 8342542f5fSchristos char *line = NULL; 8442542f5fSchristos 8542542f5fSchristos file = fopen(path, "r"); 8642542f5fSchristos if (file == NULL) 8742542f5fSchristos return 0; 8842542f5fSchristos 8942542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] Contents of '%s':\n", path); 9042542f5fSchristos while (getline(&line, &len, file) != -1) 9142542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] %s", line); 9242542f5fSchristos 9342542f5fSchristos free(line); 9442542f5fSchristos fclose(file); 9542542f5fSchristos return 1; 9642542f5fSchristos} 9742542f5fSchristos 9842542f5fSchristosstatic int __find_debugfs(void) 9942542f5fSchristos{ 10042542f5fSchristos int i; 10142542f5fSchristos 10242542f5fSchristos for (i = 0; i < DRM_MAX_MINOR; i++) { 10342542f5fSchristos char path[80]; 10442542f5fSchristos 10542542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 10642542f5fSchristos if (access(path, R_OK) == 0) 10742542f5fSchristos return i; 10842542f5fSchristos 10942542f5fSchristos sprintf(path, "/debug/dri/%d/i915_wedged", i); 11042542f5fSchristos if (access(path, R_OK) == 0) 11142542f5fSchristos return i; 11242542f5fSchristos } 11342542f5fSchristos 11442542f5fSchristos return -1; 11542542f5fSchristos} 11642542f5fSchristos 11742542f5fSchristosstatic int drm_get_minor(int fd) 11842542f5fSchristos{ 11942542f5fSchristos struct stat st; 12042542f5fSchristos 12142542f5fSchristos if (fstat(fd, &st)) 12242542f5fSchristos return __find_debugfs(); 12342542f5fSchristos 12442542f5fSchristos if (!S_ISCHR(st.st_mode)) 12542542f5fSchristos return __find_debugfs(); 12642542f5fSchristos 12742542f5fSchristos return st.st_rdev & 0x63; 12842542f5fSchristos} 12942542f5fSchristos 13042542f5fSchristos#if __linux__ 13142542f5fSchristos#include <sys/mount.h> 13242542f5fSchristos 13342542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) 13442542f5fSchristos{ 13542542f5fSchristos char path[80]; 13642542f5fSchristos int minor; 13742542f5fSchristos 13842542f5fSchristos minor = drm_get_minor(fd); 13942542f5fSchristos if (minor < 0) 14042542f5fSchristos return; 14142542f5fSchristos 14242542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 14342542f5fSchristos if (dump_file(scrn, path)) 14442542f5fSchristos return; 14542542f5fSchristos 14642542f5fSchristos sprintf(path, "/debug/dri/%d/%s", minor, name); 14742542f5fSchristos if (dump_file(scrn, path)) 14842542f5fSchristos return; 14942542f5fSchristos 15042542f5fSchristos if (mount("X-debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0) { 15142542f5fSchristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 15242542f5fSchristos dump_file(scrn, path); 15342542f5fSchristos umount("X-debug"); 15442542f5fSchristos return; 15542542f5fSchristos } 15642542f5fSchristos} 15742542f5fSchristos#else 15842542f5fSchristosstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) { } 15942542f5fSchristos#endif 16042542f5fSchristos 16142542f5fSchristosstatic void dump_clients_info(ScrnInfoPtr scrn, int fd) 16242542f5fSchristos{ 16342542f5fSchristos dump_debugfs(scrn, fd, "clients"); 16442542f5fSchristos} 16542542f5fSchristos 16642542f5fSchristosstatic int __intel_get_device_id(int fd) 16742542f5fSchristos{ 16842542f5fSchristos struct drm_i915_getparam gp; 16942542f5fSchristos int devid = 0; 17042542f5fSchristos 17142542f5fSchristos VG_CLEAR(gp); 17242542f5fSchristos gp.param = I915_PARAM_CHIPSET_ID; 17342542f5fSchristos gp.value = &devid; 17442542f5fSchristos 17542542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 17642542f5fSchristos return 0; 17742542f5fSchristos 17842542f5fSchristos return devid; 17942542f5fSchristos} 18042542f5fSchristos 18142542f5fSchristosint intel_entity_get_devid(int idx) 18242542f5fSchristos{ 18342542f5fSchristos struct intel_device *dev; 18442542f5fSchristos 18542542f5fSchristos dev = xf86GetEntityPrivate(idx, intel_device_key)->ptr; 18642542f5fSchristos if (dev == NULL) 18742542f5fSchristos return 0; 18842542f5fSchristos 18913496ba1Ssnj return dev->device_id; 19042542f5fSchristos} 19142542f5fSchristos 19203b705cfSriastradhstatic inline struct intel_device *intel_device(ScrnInfoPtr scrn) 19303b705cfSriastradh{ 19403b705cfSriastradh if (scrn->entityList == NULL) 19503b705cfSriastradh return NULL; 19603b705cfSriastradh 19703b705cfSriastradh return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 19803b705cfSriastradh} 19903b705cfSriastradh 20042542f5fSchristosstatic int is_i915_device(int fd) 20103b705cfSriastradh{ 20203b705cfSriastradh drm_version_t version; 20303b705cfSriastradh char name[5] = ""; 20403b705cfSriastradh 20503b705cfSriastradh memset(&version, 0, sizeof(version)); 20603b705cfSriastradh version.name_len = 4; 20703b705cfSriastradh version.name = name; 20803b705cfSriastradh 20903b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 21042542f5fSchristos return 0; 21103b705cfSriastradh 21203b705cfSriastradh return strcmp("i915", name) == 0; 21303b705cfSriastradh} 21403b705cfSriastradh 21542542f5fSchristosstatic int is_i915_gem(int fd) 21603b705cfSriastradh{ 21742542f5fSchristos int ret = is_i915_device(fd); 21803b705cfSriastradh 21903b705cfSriastradh if (ret) { 22003b705cfSriastradh struct drm_i915_getparam gp; 22142542f5fSchristos 22242542f5fSchristos VG_CLEAR(gp); 22303b705cfSriastradh gp.param = I915_PARAM_HAS_GEM; 22403b705cfSriastradh gp.value = &ret; 22542542f5fSchristos 22603b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 22742542f5fSchristos ret = 0; 22803b705cfSriastradh } 22942542f5fSchristos 23042542f5fSchristos return ret; 23142542f5fSchristos} 23242542f5fSchristos 23342542f5fSchristosstatic int __intel_check_device(int fd) 23442542f5fSchristos{ 23542542f5fSchristos int ret; 23642542f5fSchristos 23742542f5fSchristos /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 23842542f5fSchristos ret = is_i915_gem(fd); 23903b705cfSriastradh if (ret && !hosted()) { 24003b705cfSriastradh struct drm_mode_card_res res; 24103b705cfSriastradh 24203b705cfSriastradh memset(&res, 0, sizeof(res)); 24303b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 24442542f5fSchristos ret = 0; 24503b705cfSriastradh } 24603b705cfSriastradh 24703b705cfSriastradh return ret; 24803b705cfSriastradh} 24903b705cfSriastradh 25042542f5fSchristosstatic int open_cloexec(const char *path) 25103b705cfSriastradh{ 25242542f5fSchristos struct stat st; 25342542f5fSchristos int loop = 1000; 25442542f5fSchristos int fd; 25503b705cfSriastradh 25642542f5fSchristos /* No file? Assume the driver is loading slowly */ 25742542f5fSchristos while (stat(path, &st) == -1 && errno == ENOENT && --loop) 25842542f5fSchristos usleep(50000); 25942542f5fSchristos 26042542f5fSchristos if (loop != 1000) 26142542f5fSchristos ErrorF("intel: waited %d ms for '%s' to appear\n", 26242542f5fSchristos (1000 - loop) * 50, path); 26342542f5fSchristos 26442542f5fSchristos fd = -1; 26542542f5fSchristos#ifdef O_CLOEXEC 26642542f5fSchristos fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC); 26742542f5fSchristos#endif 26803b705cfSriastradh if (fd == -1) 26942542f5fSchristos fd = fd_set_cloexec(open(path, O_RDWR | O_NONBLOCK)); 27003b705cfSriastradh 27142542f5fSchristos return fd; 27242542f5fSchristos} 27342542f5fSchristos 27442542f5fSchristos#ifdef __linux__ 27542542f5fSchristosstatic int __intel_open_device__major_minor(int _major, int _minor) 27642542f5fSchristos{ 27742542f5fSchristos char path[256]; 27842542f5fSchristos DIR *dir; 27942542f5fSchristos struct dirent *de; 28042542f5fSchristos int base, fd = -1; 28142542f5fSchristos 28242542f5fSchristos base = sprintf(path, "/dev/dri/"); 28342542f5fSchristos 28442542f5fSchristos dir = opendir(path); 28542542f5fSchristos if (dir == NULL) 28642542f5fSchristos return -1; 28742542f5fSchristos 28842542f5fSchristos while ((de = readdir(dir)) != NULL) { 28942542f5fSchristos struct stat st; 29042542f5fSchristos 29142542f5fSchristos if (*de->d_name == '.') 29242542f5fSchristos continue; 29342542f5fSchristos 29442542f5fSchristos sprintf(path + base, "%s", de->d_name); 29542542f5fSchristos if (stat(path, &st) == 0 && 29642542f5fSchristos major(st.st_rdev) == _major && 29742542f5fSchristos minor(st.st_rdev) == _minor) { 29842542f5fSchristos fd = open_cloexec(path); 29942542f5fSchristos break; 30042542f5fSchristos } 30103b705cfSriastradh } 30242542f5fSchristos 30342542f5fSchristos closedir(dir); 30403b705cfSriastradh 30503b705cfSriastradh return fd; 30603b705cfSriastradh} 30703b705cfSriastradh 30842542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) 30903b705cfSriastradh{ 31042542f5fSchristos struct stat st; 31142542f5fSchristos char path[256]; 31242542f5fSchristos DIR *dir; 31342542f5fSchristos struct dirent *de; 31442542f5fSchristos int base; 31503b705cfSriastradh int fd; 31603b705cfSriastradh 31742542f5fSchristos /* Look up the major:minor for the drm device through sysfs. 31842542f5fSchristos * First we need to check that sysfs is available, then 31942542f5fSchristos * check that we have loaded our driver. When we are happy 32042542f5fSchristos * that our KMS module is loaded, we can then search for our 32142542f5fSchristos * device node. We make the assumption that it uses the same 32242542f5fSchristos * name, but after that we read the major:minor assigned to us 32342542f5fSchristos * and search for a matching entry in /dev. 32442542f5fSchristos */ 32542542f5fSchristos 32642542f5fSchristos base = sprintf(path, 32742542f5fSchristos "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 32842542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 32942542f5fSchristos if (stat(path, &st)) 33042542f5fSchristos return -1; 33103b705cfSriastradh 33242542f5fSchristos sprintf(path + base, "drm"); 33342542f5fSchristos dir = opendir(path); 33442542f5fSchristos if (dir == NULL) { 33542542f5fSchristos int loop = 0; 33603b705cfSriastradh 33742542f5fSchristos sprintf(path + base, "driver"); 33842542f5fSchristos if (stat(path, &st)) { 33903b705cfSriastradh if (xf86LoadKernelModule("i915")) 34003b705cfSriastradh return -1; 34103b705cfSriastradh (void)xf86LoadKernelModule("fbcon"); 34203b705cfSriastradh } 34303b705cfSriastradh 34442542f5fSchristos sprintf(path + base, "drm"); 34542542f5fSchristos while ((dir = opendir(path)) == NULL && loop++ < 100) 34642542f5fSchristos usleep(20000); 34742542f5fSchristos 34842542f5fSchristos ErrorF("intel: waited %d ms for i915.ko driver to load\n", loop * 20000 / 1000); 34942542f5fSchristos 35042542f5fSchristos if (dir == NULL) 35142542f5fSchristos return -1; 35242542f5fSchristos } 35342542f5fSchristos 35442542f5fSchristos fd = -1; 35542542f5fSchristos while ((de = readdir(dir)) != NULL) { 35642542f5fSchristos if (*de->d_name == '.') 35742542f5fSchristos continue; 35842542f5fSchristos 35942542f5fSchristos if (strncmp(de->d_name, "card", 4) == 0) { 36042542f5fSchristos sprintf(path + base + 4, "/dev/dri/%s", de->d_name); 36142542f5fSchristos fd = open_cloexec(path + base + 4); 36242542f5fSchristos if (fd != -1) 36342542f5fSchristos break; 36442542f5fSchristos 36542542f5fSchristos sprintf(path + base + 3, "/%s/dev", de->d_name); 36642542f5fSchristos fd = open(path, O_RDONLY); 36742542f5fSchristos if (fd == -1) 36842542f5fSchristos break; 36942542f5fSchristos 37042542f5fSchristos base = read(fd, path, sizeof(path) - 1); 37142542f5fSchristos close(fd); 37242542f5fSchristos 37342542f5fSchristos fd = -1; 37442542f5fSchristos if (base > 0) { 37542542f5fSchristos int major, minor; 37642542f5fSchristos path[base] = '\0'; 37742542f5fSchristos if (sscanf(path, "%d:%d", &major, &minor) == 2) 37842542f5fSchristos fd = __intel_open_device__major_minor(major, minor); 37903b705cfSriastradh } 38042542f5fSchristos break; 38103b705cfSriastradh } 38242542f5fSchristos } 38342542f5fSchristos closedir(dir); 38442542f5fSchristos 38542542f5fSchristos return fd; 38642542f5fSchristos} 38703b705cfSriastradh#else 38842542f5fSchristosstatic int __intel_open_device__pci(const struct pci_device *pci) { return -1; } 38903b705cfSriastradh#endif 39042542f5fSchristos 39142542f5fSchristosstatic int __intel_open_device__legacy(const struct pci_device *pci) 39242542f5fSchristos{ 39342542f5fSchristos char id[20]; 39442542f5fSchristos int ret; 39542542f5fSchristos 39642542f5fSchristos snprintf(id, sizeof(id), 39742542f5fSchristos "pci:%04x:%02x:%02x.%d", 39842542f5fSchristos pci->domain, pci->bus, pci->dev, pci->func); 39942542f5fSchristos 40042542f5fSchristos ret = drmCheckModesettingSupported(id); 40142542f5fSchristos if (ret) { 40242542f5fSchristos if (xf86LoadKernelModule("i915")) 40342542f5fSchristos ret = drmCheckModesettingSupported(id); 40442542f5fSchristos if (ret) 40542542f5fSchristos return -1; 40642542f5fSchristos /* Be nice to the user and load fbcon too */ 40742542f5fSchristos (void)xf86LoadKernelModule("fbcon"); 40803b705cfSriastradh } 40903b705cfSriastradh 41042542f5fSchristos return fd_set_nonblock(drmOpen(NULL, id)); 41142542f5fSchristos} 41242542f5fSchristos 41342542f5fSchristosstatic int __intel_open_device(const struct pci_device *pci, const char *path) 41442542f5fSchristos{ 41542542f5fSchristos int fd; 41642542f5fSchristos 41742542f5fSchristos if (path == NULL) { 41842542f5fSchristos if (pci == NULL) 41942542f5fSchristos return -1; 42042542f5fSchristos 42142542f5fSchristos fd = __intel_open_device__pci(pci); 42242542f5fSchristos if (fd == -1) 42342542f5fSchristos fd = __intel_open_device__legacy(pci); 42442542f5fSchristos } else 42542542f5fSchristos fd = open_cloexec(path); 42642542f5fSchristos 42703b705cfSriastradh return fd; 42803b705cfSriastradh} 42903b705cfSriastradh 43042542f5fSchristosstatic char *find_master_node(int fd) 43142542f5fSchristos{ 43242542f5fSchristos struct stat st, master; 43342542f5fSchristos char buf[128]; 43442542f5fSchristos 43542542f5fSchristos if (fstat(fd, &st)) 43642542f5fSchristos return NULL; 43742542f5fSchristos 43842542f5fSchristos if (!S_ISCHR(st.st_mode)) 43942542f5fSchristos return NULL; 44042542f5fSchristos 44142542f5fSchristos sprintf(buf, "/dev/dri/card%d", (int)(st.st_rdev & 0x7f)); 44242542f5fSchristos if (stat(buf, &master) == 0 && 44342542f5fSchristos st.st_mode == master.st_mode && 44442542f5fSchristos (st.st_rdev & 0x7f) == master.st_rdev) 44542542f5fSchristos return strdup(buf); 44642542f5fSchristos 44742542f5fSchristos /* Fallback to iterating over the usual suspects */ 44842542f5fSchristos return drmGetDeviceNameFromFd(fd); 44942542f5fSchristos} 45042542f5fSchristos 45142542f5fSchristosstatic int is_render_node(int fd, struct stat *st) 45242542f5fSchristos{ 45342542f5fSchristos if (fstat(fd, st)) 45442542f5fSchristos return 0; 45542542f5fSchristos 45642542f5fSchristos if (!S_ISCHR(st->st_mode)) 45742542f5fSchristos return 0; 45842542f5fSchristos 45942542f5fSchristos return st->st_rdev & 0x80; 46042542f5fSchristos} 46142542f5fSchristos 46242542f5fSchristosstatic char *find_render_node(int fd) 46342542f5fSchristos{ 46442542f5fSchristos#if defined(USE_RENDERNODE) 46542542f5fSchristos struct stat master, render; 46642542f5fSchristos char buf[128]; 46742542f5fSchristos 46842542f5fSchristos /* Are we a render-node ourselves? */ 46942542f5fSchristos if (is_render_node(fd, &master)) 47042542f5fSchristos return NULL; 47142542f5fSchristos 47242542f5fSchristos sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf)); 47342542f5fSchristos if (stat(buf, &render) == 0 && 47442542f5fSchristos master.st_mode == render.st_mode && 47542542f5fSchristos render.st_rdev == ((master.st_rdev | 0x80) & 0xbf)) 47642542f5fSchristos return strdup(buf); 47742542f5fSchristos#endif 47842542f5fSchristos 47942542f5fSchristos return NULL; 48042542f5fSchristos} 48142542f5fSchristos 48242542f5fSchristos#if defined(ODEV_ATTRIB_PATH) 48342542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 48442542f5fSchristos{ 48542542f5fSchristos const char *path; 48642542f5fSchristos 48742542f5fSchristos if (dev == NULL) 48842542f5fSchristos return NULL; 48942542f5fSchristos 49042542f5fSchristos path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH); 49142542f5fSchristos if (path == NULL) 49242542f5fSchristos return NULL; 49342542f5fSchristos 49442542f5fSchristos return strdup(path); 49542542f5fSchristos} 49642542f5fSchristos 49742542f5fSchristos#else 49842542f5fSchristos 49942542f5fSchristosstatic char *get_path(struct xf86_platform_device *dev) 50042542f5fSchristos{ 50142542f5fSchristos return NULL; 50242542f5fSchristos} 50342542f5fSchristos#endif 50442542f5fSchristos 50542542f5fSchristos 50642542f5fSchristos#if defined(ODEV_ATTRIB_FD) 50742542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 50842542f5fSchristos{ 50942542f5fSchristos if (dev == NULL) 51042542f5fSchristos return -1; 51142542f5fSchristos 51242542f5fSchristos return xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1); 51342542f5fSchristos} 51442542f5fSchristos 51542542f5fSchristos#else 51642542f5fSchristos 51742542f5fSchristosstatic int get_fd(struct xf86_platform_device *dev) 51842542f5fSchristos{ 51942542f5fSchristos return -1; 52042542f5fSchristos} 52142542f5fSchristos#endif 52242542f5fSchristos 52342542f5fSchristosstatic int is_master(int fd) 52442542f5fSchristos{ 52542542f5fSchristos drmSetVersion sv; 52642542f5fSchristos 52742542f5fSchristos sv.drm_di_major = 1; 52842542f5fSchristos sv.drm_di_minor = 1; 52942542f5fSchristos sv.drm_dd_major = -1; 53042542f5fSchristos sv.drm_dd_minor = -1; 53142542f5fSchristos 53242542f5fSchristos return drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv) == 0; 53342542f5fSchristos} 53442542f5fSchristos 53503b705cfSriastradhint intel_open_device(int entity_num, 53603b705cfSriastradh const struct pci_device *pci, 53742542f5fSchristos struct xf86_platform_device *platform) 53803b705cfSriastradh{ 53903b705cfSriastradh struct intel_device *dev; 54042542f5fSchristos char *path; 54142542f5fSchristos int fd, master_count; 54203b705cfSriastradh 54303b705cfSriastradh if (intel_device_key == -1) 54403b705cfSriastradh intel_device_key = xf86AllocateEntityPrivateIndex(); 54503b705cfSriastradh if (intel_device_key == -1) 54603b705cfSriastradh return -1; 54703b705cfSriastradh 54803b705cfSriastradh dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 54903b705cfSriastradh if (dev) 55003b705cfSriastradh return dev->fd; 55103b705cfSriastradh 55242542f5fSchristos path = get_path(platform); 55303b705cfSriastradh 55442542f5fSchristos master_count = 1; /* DRM_MASTER is managed by Xserver */ 55542542f5fSchristos fd = get_fd(platform); 55642542f5fSchristos if (fd == -1) { 55742542f5fSchristos fd = __intel_open_device(pci, path); 55842542f5fSchristos if (fd == -1) 55942542f5fSchristos goto err_path; 56042542f5fSchristos 56142542f5fSchristos master_count = 0; 56242542f5fSchristos } 56342542f5fSchristos 56442542f5fSchristos if (path == NULL) { 56542542f5fSchristos path = find_master_node(fd); 56642542f5fSchristos if (path == NULL) 56742542f5fSchristos goto err_close; 56842542f5fSchristos } 56903b705cfSriastradh 57003b705cfSriastradh if (!__intel_check_device(fd)) 57103b705cfSriastradh goto err_close; 57203b705cfSriastradh 57303b705cfSriastradh dev = malloc(sizeof(*dev)); 57403b705cfSriastradh if (dev == NULL) 57503b705cfSriastradh goto err_close; 57603b705cfSriastradh 57703b705cfSriastradh /* If hosted under a system compositor, just pretend to be master */ 57842542f5fSchristos if (hosted()) 57942542f5fSchristos master_count++; 58042542f5fSchristos 58142542f5fSchristos /* Non-root user holding MASTER, don't let go */ 58242542f5fSchristos if (geteuid() && is_master(fd)) 58342542f5fSchristos master_count++; 58442542f5fSchristos 58513496ba1Ssnj if (pci) 58613496ba1Ssnj dev->device_id = pci->device_id; 58713496ba1Ssnj else 58813496ba1Ssnj dev->device_id = __intel_get_device_id(fd); 58913496ba1Ssnj 59013496ba1Ssnj dev->idx = entity_num; 59142542f5fSchristos dev->fd = fd; 59242542f5fSchristos dev->open_count = master_count; 59342542f5fSchristos dev->master_count = master_count; 59442542f5fSchristos dev->master_node = path; 59542542f5fSchristos dev->render_node = find_render_node(fd); 59642542f5fSchristos if (dev->render_node == NULL) 59742542f5fSchristos dev->render_node = dev->master_node; 59803b705cfSriastradh 59903b705cfSriastradh xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 60003b705cfSriastradh 60103b705cfSriastradh return fd; 60203b705cfSriastradh 60303b705cfSriastradherr_close: 60442542f5fSchristos if (master_count == 0) /* Don't close server-fds */ 60542542f5fSchristos close(fd); 60603b705cfSriastradherr_path: 60742542f5fSchristos free(path); 60803b705cfSriastradh return -1; 60903b705cfSriastradh} 61003b705cfSriastradh 61142542f5fSchristosint __intel_peek_fd(ScrnInfoPtr scrn) 61242542f5fSchristos{ 61342542f5fSchristos struct intel_device *dev; 61442542f5fSchristos 61542542f5fSchristos dev = intel_device(scrn); 61642542f5fSchristos assert(dev && dev->fd != -1); 61742542f5fSchristos 61842542f5fSchristos return dev->fd; 61942542f5fSchristos} 62042542f5fSchristos 62113496ba1Ssnjint intel_has_render_node(struct intel_device *dev) 62242542f5fSchristos{ 62342542f5fSchristos struct stat st; 62442542f5fSchristos 62542542f5fSchristos assert(dev && dev->fd != -1); 62642542f5fSchristos return is_render_node(dev->fd, &st); 62742542f5fSchristos} 62842542f5fSchristos 62913496ba1Ssnjstruct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd) 63003b705cfSriastradh{ 63103b705cfSriastradh struct intel_device *dev; 63203b705cfSriastradh int ret; 63303b705cfSriastradh 63403b705cfSriastradh dev = intel_device(scrn); 63513496ba1Ssnj if (dev == NULL) 63613496ba1Ssnj return NULL; 63713496ba1Ssnj 63813496ba1Ssnj assert(dev->fd != -1); 63903b705cfSriastradh 64003b705cfSriastradh if (dev->open_count++ == 0) { 64103b705cfSriastradh drmSetVersion sv; 64203b705cfSriastradh int retry = 2000; 64303b705cfSriastradh 64403b705cfSriastradh assert(!hosted()); 64503b705cfSriastradh 64603b705cfSriastradh /* Check that what we opened was a master or a 64703b705cfSriastradh * master-capable FD, by setting the version of the 64803b705cfSriastradh * interface we'll use to talk to it. 64903b705cfSriastradh */ 65003b705cfSriastradh do { 65103b705cfSriastradh sv.drm_di_major = 1; 65203b705cfSriastradh sv.drm_di_minor = 1; 65303b705cfSriastradh sv.drm_dd_major = -1; 65403b705cfSriastradh sv.drm_dd_minor = -1; 65503b705cfSriastradh ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 65603b705cfSriastradh if (ret == 0) 65703b705cfSriastradh break; 65803b705cfSriastradh 65903b705cfSriastradh usleep(1000); 66003b705cfSriastradh } while (--retry); 66103b705cfSriastradh if (ret != 0) { 66203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 66303b705cfSriastradh "[drm] failed to set drm interface version: %s [%d].\n", 66403b705cfSriastradh strerror(errno), errno); 66542542f5fSchristos dump_clients_info(scrn, dev->fd); 66603b705cfSriastradh dev->open_count--; 66713496ba1Ssnj return NULL; 66803b705cfSriastradh } 66903b705cfSriastradh } 67003b705cfSriastradh 67113496ba1Ssnj *fd = dev->fd; 67213496ba1Ssnj return dev; 67303b705cfSriastradh} 67403b705cfSriastradh 67513496ba1Ssnjconst char *intel_get_client_name(struct intel_device *dev) 67642542f5fSchristos{ 67742542f5fSchristos assert(dev && dev->render_node); 67842542f5fSchristos return dev->render_node; 67942542f5fSchristos} 68042542f5fSchristos 68142542f5fSchristosstatic int authorise(struct intel_device *dev, int fd) 68242542f5fSchristos{ 68342542f5fSchristos struct stat st; 68442542f5fSchristos drm_magic_t magic; 68542542f5fSchristos 68642542f5fSchristos if (is_render_node(fd, &st)) /* restricted authority, do not elevate */ 68742542f5fSchristos return 1; 68842542f5fSchristos 68942542f5fSchristos return drmGetMagic(fd, &magic) == 0 && drmAuthMagic(dev->fd, magic) == 0; 69042542f5fSchristos} 69142542f5fSchristos 69213496ba1Ssnjint intel_get_client_fd(struct intel_device *dev) 69342542f5fSchristos{ 69442542f5fSchristos int fd = -1; 69542542f5fSchristos 69613496ba1Ssnj assert(dev && 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 71713496ba1Ssnjint intel_get_device_id(struct intel_device *dev) 71803b705cfSriastradh{ 71942542f5fSchristos assert(dev && dev->fd != -1); 72013496ba1Ssnj return dev->device_id; 72103b705cfSriastradh} 72203b705cfSriastradh 72313496ba1Ssnjint intel_get_master(struct intel_device *dev) 72403b705cfSriastradh{ 72503b705cfSriastradh int ret; 72603b705cfSriastradh 72703b705cfSriastradh assert(dev && dev->fd != -1); 72803b705cfSriastradh 72903b705cfSriastradh ret = 0; 73003b705cfSriastradh if (dev->master_count++ == 0) { 73103b705cfSriastradh int retry = 2000; 73203b705cfSriastradh 73303b705cfSriastradh assert(!hosted()); 73403b705cfSriastradh do { 73503b705cfSriastradh ret = drmSetMaster(dev->fd); 73603b705cfSriastradh if (ret == 0) 73703b705cfSriastradh break; 73803b705cfSriastradh usleep(1000); 73903b705cfSriastradh } while (--retry); 74003b705cfSriastradh } 74103b705cfSriastradh 74203b705cfSriastradh return ret; 74303b705cfSriastradh} 74403b705cfSriastradh 74513496ba1Ssnjint intel_put_master(struct intel_device *dev) 74603b705cfSriastradh{ 74703b705cfSriastradh int ret; 74803b705cfSriastradh 74903b705cfSriastradh assert(dev && dev->fd != -1); 75003b705cfSriastradh 75103b705cfSriastradh ret = 0; 75203b705cfSriastradh assert(dev->master_count); 75303b705cfSriastradh if (--dev->master_count == 0) { 75403b705cfSriastradh assert(!hosted()); 75503b705cfSriastradh assert(drmSetMaster(dev->fd) == 0); 75603b705cfSriastradh ret = drmDropMaster(dev->fd); 75703b705cfSriastradh } 75803b705cfSriastradh 75903b705cfSriastradh return ret; 76003b705cfSriastradh} 76103b705cfSriastradh 76213496ba1Ssnjvoid intel_put_device(struct intel_device *dev) 76303b705cfSriastradh{ 76403b705cfSriastradh assert(dev && dev->fd != -1); 76503b705cfSriastradh 76603b705cfSriastradh assert(dev->open_count); 76703b705cfSriastradh if (--dev->open_count) 76803b705cfSriastradh return; 76903b705cfSriastradh 77003b705cfSriastradh assert(!hosted()); 77113496ba1Ssnj xf86GetEntityPrivate(dev->idx, intel_device_key)->ptr = NULL; 77203b705cfSriastradh 77303b705cfSriastradh drmClose(dev->fd); 77442542f5fSchristos if (dev->render_node != dev->master_node) 77542542f5fSchristos free(dev->render_node); 77642542f5fSchristos free(dev->master_node); 77703b705cfSriastradh free(dev); 77803b705cfSriastradh} 779