intel_device.c revision 428d7b3d
1428d7b3dSmrg/*************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrg Copyright 2013 Intel Corporation. All Rights Reserved. 4428d7b3dSmrg 5428d7b3dSmrg Permission is hereby granted, free of charge, to any person obtaining a 6428d7b3dSmrg copy of this software and associated documentation files (the 7428d7b3dSmrg "Software"), to deal in the Software without restriction, including 8428d7b3dSmrg without limitation the rights to use, copy, modify, merge, publish, 9428d7b3dSmrg distribute, sub license, and/or sell copies of the Software, and to 10428d7b3dSmrg permit persons to whom the Software is furnished to do so, subject to 11428d7b3dSmrg the following conditions: 12428d7b3dSmrg 13428d7b3dSmrg The above copyright notice and this permission notice (including the 14428d7b3dSmrg next paragraph) shall be included in all copies or substantial portions 15428d7b3dSmrg of the Software. 16428d7b3dSmrg 17428d7b3dSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18428d7b3dSmrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19428d7b3dSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20428d7b3dSmrg IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21428d7b3dSmrg DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22428d7b3dSmrg OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 23428d7b3dSmrg THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24428d7b3dSmrg 25428d7b3dSmrg **************************************************************************/ 26428d7b3dSmrg 27428d7b3dSmrg#ifdef HAVE_CONFIG_H 28428d7b3dSmrg#include "config.h" 29428d7b3dSmrg#endif 30428d7b3dSmrg 31428d7b3dSmrg#include <sys/types.h> 32428d7b3dSmrg#include <sys/stat.h> 33428d7b3dSmrg#include <assert.h> 34428d7b3dSmrg#include <string.h> 35428d7b3dSmrg#include <unistd.h> 36428d7b3dSmrg#include <fcntl.h> 37428d7b3dSmrg#include <stdlib.h> 38428d7b3dSmrg#include <dirent.h> 39428d7b3dSmrg#include <errno.h> 40428d7b3dSmrg 41428d7b3dSmrg#include <pciaccess.h> 42428d7b3dSmrg 43428d7b3dSmrg#include <xorg-server.h> 44428d7b3dSmrg#include <xf86.h> 45428d7b3dSmrg#include <xf86drm.h> 46428d7b3dSmrg#include <xf86drmMode.h> 47428d7b3dSmrg#include <xf86_OSproc.h> 48428d7b3dSmrg#include <i915_drm.h> 49428d7b3dSmrg 50428d7b3dSmrg#ifdef XSERVER_PLATFORM_BUS 51428d7b3dSmrg#include <xf86platformBus.h> 52428d7b3dSmrg#endif 53428d7b3dSmrg 54428d7b3dSmrg#ifdef HAVE_VALGRIND 55428d7b3dSmrg#include <valgrind.h> 56428d7b3dSmrg#include <memcheck.h> 57428d7b3dSmrg#define VG(x) x 58428d7b3dSmrg#else 59428d7b3dSmrg#define VG(x) 60428d7b3dSmrg#endif 61428d7b3dSmrg 62428d7b3dSmrg#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) 63428d7b3dSmrg 64428d7b3dSmrg#include "intel_driver.h" 65428d7b3dSmrg#include "fd.h" 66428d7b3dSmrg 67428d7b3dSmrgstruct intel_device { 68428d7b3dSmrg int idx; 69428d7b3dSmrg char *master_node; 70428d7b3dSmrg char *render_node; 71428d7b3dSmrg int fd; 72428d7b3dSmrg int device_id; 73428d7b3dSmrg int open_count; 74428d7b3dSmrg int master_count; 75428d7b3dSmrg}; 76428d7b3dSmrg 77428d7b3dSmrgstatic int intel_device_key = -1; 78428d7b3dSmrg 79428d7b3dSmrgstatic int dump_file(ScrnInfoPtr scrn, const char *path) 80428d7b3dSmrg{ 81428d7b3dSmrg FILE *file; 82428d7b3dSmrg size_t len = 0; 83428d7b3dSmrg char *line = NULL; 84428d7b3dSmrg 85428d7b3dSmrg file = fopen(path, "r"); 86428d7b3dSmrg if (file == NULL) 87428d7b3dSmrg return 0; 88428d7b3dSmrg 89428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] Contents of '%s':\n", path); 90428d7b3dSmrg while (getline(&line, &len, file) != -1) 91428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] %s", line); 92428d7b3dSmrg 93428d7b3dSmrg free(line); 94428d7b3dSmrg fclose(file); 95428d7b3dSmrg return 1; 96428d7b3dSmrg} 97428d7b3dSmrg 98428d7b3dSmrgstatic int __find_debugfs(void) 99428d7b3dSmrg{ 100428d7b3dSmrg int i; 101428d7b3dSmrg 102428d7b3dSmrg for (i = 0; i < DRM_MAX_MINOR; i++) { 103428d7b3dSmrg char path[80]; 104428d7b3dSmrg 105428d7b3dSmrg sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 106428d7b3dSmrg if (access(path, R_OK) == 0) 107428d7b3dSmrg return i; 108428d7b3dSmrg 109428d7b3dSmrg sprintf(path, "/debug/dri/%d/i915_wedged", i); 110428d7b3dSmrg if (access(path, R_OK) == 0) 111428d7b3dSmrg return i; 112428d7b3dSmrg } 113428d7b3dSmrg 114428d7b3dSmrg return -1; 115428d7b3dSmrg} 116428d7b3dSmrg 117428d7b3dSmrgstatic int drm_get_minor(int fd) 118428d7b3dSmrg{ 119428d7b3dSmrg struct stat st; 120428d7b3dSmrg 121428d7b3dSmrg if (fstat(fd, &st)) 122428d7b3dSmrg return __find_debugfs(); 123428d7b3dSmrg 124428d7b3dSmrg if (!S_ISCHR(st.st_mode)) 125428d7b3dSmrg return __find_debugfs(); 126428d7b3dSmrg 127428d7b3dSmrg return st.st_rdev & 0x63; 128428d7b3dSmrg} 129428d7b3dSmrg 130428d7b3dSmrg#if __linux__ 131428d7b3dSmrg#include <sys/mount.h> 132428d7b3dSmrg 133428d7b3dSmrgstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) 134428d7b3dSmrg{ 135428d7b3dSmrg char path[80]; 136428d7b3dSmrg int minor; 137428d7b3dSmrg 138428d7b3dSmrg minor = drm_get_minor(fd); 139428d7b3dSmrg if (minor < 0) 140428d7b3dSmrg return; 141428d7b3dSmrg 142428d7b3dSmrg sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 143428d7b3dSmrg if (dump_file(scrn, path)) 144428d7b3dSmrg return; 145428d7b3dSmrg 146428d7b3dSmrg sprintf(path, "/debug/dri/%d/%s", minor, name); 147428d7b3dSmrg if (dump_file(scrn, path)) 148428d7b3dSmrg return; 149428d7b3dSmrg 150428d7b3dSmrg if (mount("X-debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0) { 151428d7b3dSmrg sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 152428d7b3dSmrg dump_file(scrn, path); 153428d7b3dSmrg umount("X-debug"); 154428d7b3dSmrg return; 155428d7b3dSmrg } 156428d7b3dSmrg} 157428d7b3dSmrg#else 158428d7b3dSmrgstatic void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) { } 159428d7b3dSmrg#endif 160428d7b3dSmrg 161428d7b3dSmrgstatic void dump_clients_info(ScrnInfoPtr scrn, int fd) 162428d7b3dSmrg{ 163428d7b3dSmrg dump_debugfs(scrn, fd, "clients"); 164428d7b3dSmrg} 165428d7b3dSmrg 166428d7b3dSmrgstatic int __intel_get_device_id(int fd) 167428d7b3dSmrg{ 168428d7b3dSmrg struct drm_i915_getparam gp; 169428d7b3dSmrg int devid = 0; 170428d7b3dSmrg 171428d7b3dSmrg VG_CLEAR(gp); 172428d7b3dSmrg gp.param = I915_PARAM_CHIPSET_ID; 173428d7b3dSmrg gp.value = &devid; 174428d7b3dSmrg 175428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 176428d7b3dSmrg return 0; 177428d7b3dSmrg 178428d7b3dSmrg return devid; 179428d7b3dSmrg} 180428d7b3dSmrg 181428d7b3dSmrgint intel_entity_get_devid(int idx) 182428d7b3dSmrg{ 183428d7b3dSmrg struct intel_device *dev; 184428d7b3dSmrg 185428d7b3dSmrg dev = xf86GetEntityPrivate(idx, intel_device_key)->ptr; 186428d7b3dSmrg if (dev == NULL) 187428d7b3dSmrg return 0; 188428d7b3dSmrg 189428d7b3dSmrg return dev->device_id; 190428d7b3dSmrg} 191428d7b3dSmrg 192428d7b3dSmrgstatic inline struct intel_device *intel_device(ScrnInfoPtr scrn) 193428d7b3dSmrg{ 194428d7b3dSmrg if (scrn->entityList == NULL) 195428d7b3dSmrg return NULL; 196428d7b3dSmrg 197428d7b3dSmrg return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 198428d7b3dSmrg} 199428d7b3dSmrg 200428d7b3dSmrgstatic int is_i915_device(int fd) 201428d7b3dSmrg{ 202428d7b3dSmrg drm_version_t version; 203428d7b3dSmrg char name[5] = ""; 204428d7b3dSmrg 205428d7b3dSmrg memset(&version, 0, sizeof(version)); 206428d7b3dSmrg version.name_len = 4; 207428d7b3dSmrg version.name = name; 208428d7b3dSmrg 209428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 210428d7b3dSmrg return 0; 211428d7b3dSmrg 212428d7b3dSmrg return strcmp("i915", name) == 0; 213428d7b3dSmrg} 214428d7b3dSmrg 215428d7b3dSmrgstatic int is_i915_gem(int fd) 216428d7b3dSmrg{ 217428d7b3dSmrg int ret = is_i915_device(fd); 218428d7b3dSmrg 219428d7b3dSmrg if (ret) { 220428d7b3dSmrg struct drm_i915_getparam gp; 221428d7b3dSmrg 222428d7b3dSmrg VG_CLEAR(gp); 223428d7b3dSmrg gp.param = I915_PARAM_HAS_GEM; 224428d7b3dSmrg gp.value = &ret; 225428d7b3dSmrg 226428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 227428d7b3dSmrg ret = 0; 228428d7b3dSmrg } 229428d7b3dSmrg 230428d7b3dSmrg return ret; 231428d7b3dSmrg} 232428d7b3dSmrg 233428d7b3dSmrgstatic int __intel_check_device(int fd) 234428d7b3dSmrg{ 235428d7b3dSmrg int ret; 236428d7b3dSmrg 237428d7b3dSmrg /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 238428d7b3dSmrg ret = is_i915_gem(fd); 239428d7b3dSmrg if (ret && !hosted()) { 240428d7b3dSmrg struct drm_mode_card_res res; 241428d7b3dSmrg 242428d7b3dSmrg memset(&res, 0, sizeof(res)); 243428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 244428d7b3dSmrg ret = 0; 245428d7b3dSmrg } 246428d7b3dSmrg 247428d7b3dSmrg return ret; 248428d7b3dSmrg} 249428d7b3dSmrg 250428d7b3dSmrgstatic int open_cloexec(const char *path) 251428d7b3dSmrg{ 252428d7b3dSmrg struct stat st; 253428d7b3dSmrg int loop = 1000; 254428d7b3dSmrg int fd; 255428d7b3dSmrg 256428d7b3dSmrg /* No file? Assume the driver is loading slowly */ 257428d7b3dSmrg while (stat(path, &st) == -1 && errno == ENOENT && --loop) 258428d7b3dSmrg usleep(50000); 259428d7b3dSmrg 260428d7b3dSmrg if (loop != 1000) 261428d7b3dSmrg ErrorF("intel: waited %d ms for '%s' to appear\n", 262428d7b3dSmrg (1000 - loop) * 50, path); 263428d7b3dSmrg 264428d7b3dSmrg fd = -1; 265428d7b3dSmrg#ifdef O_CLOEXEC 266428d7b3dSmrg fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC); 267428d7b3dSmrg#endif 268428d7b3dSmrg if (fd == -1) 269428d7b3dSmrg fd = fd_set_cloexec(open(path, O_RDWR | O_NONBLOCK)); 270428d7b3dSmrg 271428d7b3dSmrg return fd; 272428d7b3dSmrg} 273428d7b3dSmrg 274428d7b3dSmrg#ifdef __linux__ 275428d7b3dSmrgstatic int __intel_open_device__major_minor(int _major, int _minor) 276428d7b3dSmrg{ 277428d7b3dSmrg char path[256]; 278428d7b3dSmrg DIR *dir; 279428d7b3dSmrg struct dirent *de; 280428d7b3dSmrg int base, fd = -1; 281428d7b3dSmrg 282428d7b3dSmrg base = sprintf(path, "/dev/dri/"); 283428d7b3dSmrg 284428d7b3dSmrg dir = opendir(path); 285428d7b3dSmrg if (dir == NULL) 286428d7b3dSmrg return -1; 287428d7b3dSmrg 288428d7b3dSmrg while ((de = readdir(dir)) != NULL) { 289428d7b3dSmrg struct stat st; 290428d7b3dSmrg 291428d7b3dSmrg if (*de->d_name == '.') 292428d7b3dSmrg continue; 293428d7b3dSmrg 294428d7b3dSmrg sprintf(path + base, "%s", de->d_name); 295428d7b3dSmrg if (stat(path, &st) == 0 && 296428d7b3dSmrg major(st.st_rdev) == _major && 297428d7b3dSmrg minor(st.st_rdev) == _minor) { 298428d7b3dSmrg fd = open_cloexec(path); 299428d7b3dSmrg break; 300428d7b3dSmrg } 301428d7b3dSmrg } 302428d7b3dSmrg 303428d7b3dSmrg closedir(dir); 304428d7b3dSmrg 305428d7b3dSmrg return fd; 306428d7b3dSmrg} 307428d7b3dSmrg 308428d7b3dSmrgstatic int __intel_open_device__pci(const struct pci_device *pci) 309428d7b3dSmrg{ 310428d7b3dSmrg struct stat st; 311428d7b3dSmrg char path[256]; 312428d7b3dSmrg DIR *dir; 313428d7b3dSmrg struct dirent *de; 314428d7b3dSmrg int base; 315428d7b3dSmrg int fd; 316428d7b3dSmrg 317428d7b3dSmrg /* Look up the major:minor for the drm device through sysfs. 318428d7b3dSmrg * First we need to check that sysfs is available, then 319428d7b3dSmrg * check that we have loaded our driver. When we are happy 320428d7b3dSmrg * that our KMS module is loaded, we can then search for our 321428d7b3dSmrg * device node. We make the assumption that it uses the same 322428d7b3dSmrg * name, but after that we read the major:minor assigned to us 323428d7b3dSmrg * and search for a matching entry in /dev. 324428d7b3dSmrg */ 325428d7b3dSmrg 326428d7b3dSmrg base = sprintf(path, 327428d7b3dSmrg "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 328428d7b3dSmrg pci->domain, pci->bus, pci->dev, pci->func); 329428d7b3dSmrg if (stat(path, &st)) 330428d7b3dSmrg return -1; 331428d7b3dSmrg 332428d7b3dSmrg sprintf(path + base, "drm"); 333428d7b3dSmrg dir = opendir(path); 334428d7b3dSmrg if (dir == NULL) { 335428d7b3dSmrg int loop = 0; 336428d7b3dSmrg 337428d7b3dSmrg sprintf(path + base, "driver"); 338428d7b3dSmrg if (stat(path, &st)) { 339428d7b3dSmrg if (xf86LoadKernelModule("i915")) 340428d7b3dSmrg return -1; 341428d7b3dSmrg (void)xf86LoadKernelModule("fbcon"); 342428d7b3dSmrg } 343428d7b3dSmrg 344428d7b3dSmrg sprintf(path + base, "drm"); 345428d7b3dSmrg while ((dir = opendir(path)) == NULL && loop++ < 100) 346428d7b3dSmrg usleep(20000); 347428d7b3dSmrg 348428d7b3dSmrg ErrorF("intel: waited %d ms for i915.ko driver to load\n", loop * 20000 / 1000); 349428d7b3dSmrg 350428d7b3dSmrg if (dir == NULL) 351428d7b3dSmrg return -1; 352428d7b3dSmrg } 353428d7b3dSmrg 354428d7b3dSmrg fd = -1; 355428d7b3dSmrg while ((de = readdir(dir)) != NULL) { 356428d7b3dSmrg if (*de->d_name == '.') 357428d7b3dSmrg continue; 358428d7b3dSmrg 359428d7b3dSmrg if (strncmp(de->d_name, "card", 4) == 0) { 360428d7b3dSmrg sprintf(path + base + 4, "/dev/dri/%s", de->d_name); 361428d7b3dSmrg fd = open_cloexec(path + base + 4); 362428d7b3dSmrg if (fd != -1) 363428d7b3dSmrg break; 364428d7b3dSmrg 365428d7b3dSmrg sprintf(path + base + 3, "/%s/dev", de->d_name); 366428d7b3dSmrg fd = open(path, O_RDONLY); 367428d7b3dSmrg if (fd == -1) 368428d7b3dSmrg break; 369428d7b3dSmrg 370428d7b3dSmrg base = read(fd, path, sizeof(path) - 1); 371428d7b3dSmrg close(fd); 372428d7b3dSmrg 373428d7b3dSmrg fd = -1; 374428d7b3dSmrg if (base > 0) { 375428d7b3dSmrg int major, minor; 376428d7b3dSmrg path[base] = '\0'; 377428d7b3dSmrg if (sscanf(path, "%d:%d", &major, &minor) == 2) 378428d7b3dSmrg fd = __intel_open_device__major_minor(major, minor); 379428d7b3dSmrg } 380428d7b3dSmrg break; 381428d7b3dSmrg } 382428d7b3dSmrg } 383428d7b3dSmrg closedir(dir); 384428d7b3dSmrg 385428d7b3dSmrg return fd; 386428d7b3dSmrg} 387428d7b3dSmrg#else 388428d7b3dSmrgstatic int __intel_open_device__pci(const struct pci_device *pci) { return -1; } 389428d7b3dSmrg#endif 390428d7b3dSmrg 391428d7b3dSmrgstatic int __intel_open_device__legacy(const struct pci_device *pci) 392428d7b3dSmrg{ 393428d7b3dSmrg char id[20]; 394428d7b3dSmrg int ret; 395428d7b3dSmrg 396428d7b3dSmrg snprintf(id, sizeof(id), 397428d7b3dSmrg "pci:%04x:%02x:%02x.%d", 398428d7b3dSmrg pci->domain, pci->bus, pci->dev, pci->func); 399428d7b3dSmrg 400428d7b3dSmrg ret = drmCheckModesettingSupported(id); 401428d7b3dSmrg if (ret) { 402428d7b3dSmrg if (xf86LoadKernelModule("i915")) 403428d7b3dSmrg ret = drmCheckModesettingSupported(id); 404428d7b3dSmrg if (ret) 405428d7b3dSmrg return -1; 406428d7b3dSmrg /* Be nice to the user and load fbcon too */ 407428d7b3dSmrg (void)xf86LoadKernelModule("fbcon"); 408428d7b3dSmrg } 409428d7b3dSmrg 410428d7b3dSmrg return fd_set_nonblock(drmOpen(NULL, id)); 411428d7b3dSmrg} 412428d7b3dSmrg 413428d7b3dSmrgstatic int __intel_open_device(const struct pci_device *pci, const char *path) 414428d7b3dSmrg{ 415428d7b3dSmrg int fd; 416428d7b3dSmrg 417428d7b3dSmrg if (path == NULL) { 418428d7b3dSmrg if (pci == NULL) 419428d7b3dSmrg return -1; 420428d7b3dSmrg 421428d7b3dSmrg fd = __intel_open_device__pci(pci); 422428d7b3dSmrg if (fd == -1) 423428d7b3dSmrg fd = __intel_open_device__legacy(pci); 424428d7b3dSmrg } else 425428d7b3dSmrg fd = open_cloexec(path); 426428d7b3dSmrg 427428d7b3dSmrg return fd; 428428d7b3dSmrg} 429428d7b3dSmrg 430428d7b3dSmrgstatic char *find_master_node(int fd) 431428d7b3dSmrg{ 432428d7b3dSmrg struct stat st, master; 433428d7b3dSmrg char buf[128]; 434428d7b3dSmrg 435428d7b3dSmrg if (fstat(fd, &st)) 436428d7b3dSmrg return NULL; 437428d7b3dSmrg 438428d7b3dSmrg if (!S_ISCHR(st.st_mode)) 439428d7b3dSmrg return NULL; 440428d7b3dSmrg 441428d7b3dSmrg sprintf(buf, "/dev/dri/card%d", (int)(st.st_rdev & 0x7f)); 442428d7b3dSmrg if (stat(buf, &master) == 0 && 443428d7b3dSmrg st.st_mode == master.st_mode && 444428d7b3dSmrg (st.st_rdev & 0x7f) == master.st_rdev) 445428d7b3dSmrg return strdup(buf); 446428d7b3dSmrg 447428d7b3dSmrg /* Fallback to iterating over the usual suspects */ 448428d7b3dSmrg return drmGetDeviceNameFromFd(fd); 449428d7b3dSmrg} 450428d7b3dSmrg 451428d7b3dSmrgstatic int is_render_node(int fd, struct stat *st) 452428d7b3dSmrg{ 453428d7b3dSmrg if (fstat(fd, st)) 454428d7b3dSmrg return 0; 455428d7b3dSmrg 456428d7b3dSmrg if (!S_ISCHR(st->st_mode)) 457428d7b3dSmrg return 0; 458428d7b3dSmrg 459428d7b3dSmrg return st->st_rdev & 0x80; 460428d7b3dSmrg} 461428d7b3dSmrg 462428d7b3dSmrgstatic char *find_render_node(int fd) 463428d7b3dSmrg{ 464428d7b3dSmrg#if defined(USE_RENDERNODE) 465428d7b3dSmrg struct stat master, render; 466428d7b3dSmrg char buf[128]; 467428d7b3dSmrg 468428d7b3dSmrg /* Are we a render-node ourselves? */ 469428d7b3dSmrg if (is_render_node(fd, &master)) 470428d7b3dSmrg return NULL; 471428d7b3dSmrg 472428d7b3dSmrg sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf)); 473428d7b3dSmrg if (stat(buf, &render) == 0 && 474428d7b3dSmrg master.st_mode == render.st_mode && 475428d7b3dSmrg render.st_rdev == ((master.st_rdev | 0x80) & 0xbf)) 476428d7b3dSmrg return strdup(buf); 477428d7b3dSmrg#endif 478428d7b3dSmrg 479428d7b3dSmrg return NULL; 480428d7b3dSmrg} 481428d7b3dSmrg 482428d7b3dSmrg#if defined(ODEV_ATTRIB_PATH) 483428d7b3dSmrgstatic char *get_path(struct xf86_platform_device *dev) 484428d7b3dSmrg{ 485428d7b3dSmrg const char *path; 486428d7b3dSmrg 487428d7b3dSmrg if (dev == NULL) 488428d7b3dSmrg return NULL; 489428d7b3dSmrg 490428d7b3dSmrg path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH); 491428d7b3dSmrg if (path == NULL) 492428d7b3dSmrg return NULL; 493428d7b3dSmrg 494428d7b3dSmrg return strdup(path); 495428d7b3dSmrg} 496428d7b3dSmrg 497428d7b3dSmrg#else 498428d7b3dSmrg 499428d7b3dSmrgstatic char *get_path(struct xf86_platform_device *dev) 500428d7b3dSmrg{ 501428d7b3dSmrg return NULL; 502428d7b3dSmrg} 503428d7b3dSmrg#endif 504428d7b3dSmrg 505428d7b3dSmrg 506428d7b3dSmrg#if defined(ODEV_ATTRIB_FD) 507428d7b3dSmrgstatic int get_fd(struct xf86_platform_device *dev) 508428d7b3dSmrg{ 509428d7b3dSmrg if (dev == NULL) 510428d7b3dSmrg return -1; 511428d7b3dSmrg 512428d7b3dSmrg return xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1); 513428d7b3dSmrg} 514428d7b3dSmrg 515428d7b3dSmrg#else 516428d7b3dSmrg 517428d7b3dSmrgstatic int get_fd(struct xf86_platform_device *dev) 518428d7b3dSmrg{ 519428d7b3dSmrg return -1; 520428d7b3dSmrg} 521428d7b3dSmrg#endif 522428d7b3dSmrg 523428d7b3dSmrgstatic int is_master(int fd) 524428d7b3dSmrg{ 525428d7b3dSmrg drmSetVersion sv; 526428d7b3dSmrg 527428d7b3dSmrg sv.drm_di_major = 1; 528428d7b3dSmrg sv.drm_di_minor = 1; 529428d7b3dSmrg sv.drm_dd_major = -1; 530428d7b3dSmrg sv.drm_dd_minor = -1; 531428d7b3dSmrg 532428d7b3dSmrg return drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv) == 0; 533428d7b3dSmrg} 534428d7b3dSmrg 535428d7b3dSmrgint intel_open_device(int entity_num, 536428d7b3dSmrg const struct pci_device *pci, 537428d7b3dSmrg struct xf86_platform_device *platform) 538428d7b3dSmrg{ 539428d7b3dSmrg struct intel_device *dev; 540428d7b3dSmrg char *path; 541428d7b3dSmrg int fd, master_count; 542428d7b3dSmrg 543428d7b3dSmrg if (intel_device_key == -1) 544428d7b3dSmrg intel_device_key = xf86AllocateEntityPrivateIndex(); 545428d7b3dSmrg if (intel_device_key == -1) 546428d7b3dSmrg return -1; 547428d7b3dSmrg 548428d7b3dSmrg dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 549428d7b3dSmrg if (dev) 550428d7b3dSmrg return dev->fd; 551428d7b3dSmrg 552428d7b3dSmrg path = get_path(platform); 553428d7b3dSmrg 554428d7b3dSmrg master_count = 1; /* DRM_MASTER is managed by Xserver */ 555428d7b3dSmrg fd = get_fd(platform); 556428d7b3dSmrg if (fd == -1) { 557428d7b3dSmrg fd = __intel_open_device(pci, path); 558428d7b3dSmrg if (fd == -1) 559428d7b3dSmrg goto err_path; 560428d7b3dSmrg 561428d7b3dSmrg master_count = 0; 562428d7b3dSmrg } 563428d7b3dSmrg 564428d7b3dSmrg if (path == NULL) { 565428d7b3dSmrg path = find_master_node(fd); 566428d7b3dSmrg if (path == NULL) 567428d7b3dSmrg goto err_close; 568428d7b3dSmrg } 569428d7b3dSmrg 570428d7b3dSmrg if (!__intel_check_device(fd)) 571428d7b3dSmrg goto err_close; 572428d7b3dSmrg 573428d7b3dSmrg dev = malloc(sizeof(*dev)); 574428d7b3dSmrg if (dev == NULL) 575428d7b3dSmrg goto err_close; 576428d7b3dSmrg 577428d7b3dSmrg /* If hosted under a system compositor, just pretend to be master */ 578428d7b3dSmrg if (hosted()) 579428d7b3dSmrg master_count++; 580428d7b3dSmrg 581428d7b3dSmrg /* Non-root user holding MASTER, don't let go */ 582428d7b3dSmrg if (geteuid() && is_master(fd)) 583428d7b3dSmrg master_count++; 584428d7b3dSmrg 585428d7b3dSmrg if (pci) 586428d7b3dSmrg dev->device_id = pci->device_id; 587428d7b3dSmrg else 588428d7b3dSmrg dev->device_id = __intel_get_device_id(fd); 589428d7b3dSmrg 590428d7b3dSmrg dev->idx = entity_num; 591428d7b3dSmrg dev->fd = fd; 592428d7b3dSmrg dev->open_count = master_count; 593428d7b3dSmrg dev->master_count = master_count; 594428d7b3dSmrg dev->master_node = path; 595428d7b3dSmrg dev->render_node = find_render_node(fd); 596428d7b3dSmrg if (dev->render_node == NULL) 597428d7b3dSmrg dev->render_node = dev->master_node; 598428d7b3dSmrg 599428d7b3dSmrg xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 600428d7b3dSmrg 601428d7b3dSmrg return fd; 602428d7b3dSmrg 603428d7b3dSmrgerr_close: 604428d7b3dSmrg if (master_count == 0) /* Don't close server-fds */ 605428d7b3dSmrg close(fd); 606428d7b3dSmrgerr_path: 607428d7b3dSmrg free(path); 608428d7b3dSmrg return -1; 609428d7b3dSmrg} 610428d7b3dSmrg 611428d7b3dSmrgint __intel_peek_fd(ScrnInfoPtr scrn) 612428d7b3dSmrg{ 613428d7b3dSmrg struct intel_device *dev; 614428d7b3dSmrg 615428d7b3dSmrg dev = intel_device(scrn); 616428d7b3dSmrg assert(dev && dev->fd != -1); 617428d7b3dSmrg 618428d7b3dSmrg return dev->fd; 619428d7b3dSmrg} 620428d7b3dSmrg 621428d7b3dSmrgint intel_has_render_node(struct intel_device *dev) 622428d7b3dSmrg{ 623428d7b3dSmrg struct stat st; 624428d7b3dSmrg 625428d7b3dSmrg assert(dev && dev->fd != -1); 626428d7b3dSmrg return is_render_node(dev->fd, &st); 627428d7b3dSmrg} 628428d7b3dSmrg 629428d7b3dSmrgstruct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd) 630428d7b3dSmrg{ 631428d7b3dSmrg struct intel_device *dev; 632428d7b3dSmrg int ret; 633428d7b3dSmrg 634428d7b3dSmrg dev = intel_device(scrn); 635428d7b3dSmrg if (dev == NULL) 636428d7b3dSmrg return NULL; 637428d7b3dSmrg 638428d7b3dSmrg assert(dev->fd != -1); 639428d7b3dSmrg 640428d7b3dSmrg if (dev->open_count++ == 0) { 641428d7b3dSmrg drmSetVersion sv; 642428d7b3dSmrg int retry = 2000; 643428d7b3dSmrg 644428d7b3dSmrg assert(!hosted()); 645428d7b3dSmrg 646428d7b3dSmrg /* Check that what we opened was a master or a 647428d7b3dSmrg * master-capable FD, by setting the version of the 648428d7b3dSmrg * interface we'll use to talk to it. 649428d7b3dSmrg */ 650428d7b3dSmrg do { 651428d7b3dSmrg sv.drm_di_major = 1; 652428d7b3dSmrg sv.drm_di_minor = 1; 653428d7b3dSmrg sv.drm_dd_major = -1; 654428d7b3dSmrg sv.drm_dd_minor = -1; 655428d7b3dSmrg ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 656428d7b3dSmrg if (ret == 0) 657428d7b3dSmrg break; 658428d7b3dSmrg 659428d7b3dSmrg usleep(1000); 660428d7b3dSmrg } while (--retry); 661428d7b3dSmrg if (ret != 0) { 662428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 663428d7b3dSmrg "[drm] failed to set drm interface version: %s [%d].\n", 664428d7b3dSmrg strerror(errno), errno); 665428d7b3dSmrg dump_clients_info(scrn, dev->fd); 666428d7b3dSmrg dev->open_count--; 667428d7b3dSmrg return NULL; 668428d7b3dSmrg } 669428d7b3dSmrg } 670428d7b3dSmrg 671428d7b3dSmrg *fd = dev->fd; 672428d7b3dSmrg return dev; 673428d7b3dSmrg} 674428d7b3dSmrg 675428d7b3dSmrgconst char *intel_get_client_name(struct intel_device *dev) 676428d7b3dSmrg{ 677428d7b3dSmrg assert(dev && dev->render_node); 678428d7b3dSmrg return dev->render_node; 679428d7b3dSmrg} 680428d7b3dSmrg 681428d7b3dSmrgstatic int authorise(struct intel_device *dev, int fd) 682428d7b3dSmrg{ 683428d7b3dSmrg struct stat st; 684428d7b3dSmrg drm_magic_t magic; 685428d7b3dSmrg 686428d7b3dSmrg if (is_render_node(fd, &st)) /* restricted authority, do not elevate */ 687428d7b3dSmrg return 1; 688428d7b3dSmrg 689428d7b3dSmrg return drmGetMagic(fd, &magic) == 0 && drmAuthMagic(dev->fd, magic) == 0; 690428d7b3dSmrg} 691428d7b3dSmrg 692428d7b3dSmrgint intel_get_client_fd(struct intel_device *dev) 693428d7b3dSmrg{ 694428d7b3dSmrg int fd = -1; 695428d7b3dSmrg 696428d7b3dSmrg assert(dev && dev->fd != -1); 697428d7b3dSmrg assert(dev->render_node); 698428d7b3dSmrg 699428d7b3dSmrg#ifdef O_CLOEXEC 700428d7b3dSmrg fd = open(dev->render_node, O_RDWR | O_CLOEXEC); 701428d7b3dSmrg#endif 702428d7b3dSmrg if (fd < 0) 703428d7b3dSmrg fd = fd_set_cloexec(open(dev->render_node, O_RDWR)); 704428d7b3dSmrg if (fd < 0) 705428d7b3dSmrg return -BadAlloc; 706428d7b3dSmrg 707428d7b3dSmrg if (!authorise(dev, fd)) { 708428d7b3dSmrg close(fd); 709428d7b3dSmrg return -BadMatch; 710428d7b3dSmrg } 711428d7b3dSmrg 712428d7b3dSmrg assert(is_i915_gem(fd)); 713428d7b3dSmrg 714428d7b3dSmrg return fd; 715428d7b3dSmrg} 716428d7b3dSmrg 717428d7b3dSmrgint intel_get_device_id(struct intel_device *dev) 718428d7b3dSmrg{ 719428d7b3dSmrg assert(dev && dev->fd != -1); 720428d7b3dSmrg return dev->device_id; 721428d7b3dSmrg} 722428d7b3dSmrg 723428d7b3dSmrgint intel_get_master(struct intel_device *dev) 724428d7b3dSmrg{ 725428d7b3dSmrg int ret; 726428d7b3dSmrg 727428d7b3dSmrg assert(dev && dev->fd != -1); 728428d7b3dSmrg 729428d7b3dSmrg ret = 0; 730428d7b3dSmrg if (dev->master_count++ == 0) { 731428d7b3dSmrg int retry = 2000; 732428d7b3dSmrg 733428d7b3dSmrg assert(!hosted()); 734428d7b3dSmrg do { 735428d7b3dSmrg ret = drmSetMaster(dev->fd); 736428d7b3dSmrg if (ret == 0) 737428d7b3dSmrg break; 738428d7b3dSmrg usleep(1000); 739428d7b3dSmrg } while (--retry); 740428d7b3dSmrg } 741428d7b3dSmrg 742428d7b3dSmrg return ret; 743428d7b3dSmrg} 744428d7b3dSmrg 745428d7b3dSmrgint intel_put_master(struct intel_device *dev) 746428d7b3dSmrg{ 747428d7b3dSmrg int ret; 748428d7b3dSmrg 749428d7b3dSmrg assert(dev && dev->fd != -1); 750428d7b3dSmrg 751428d7b3dSmrg ret = 0; 752428d7b3dSmrg assert(dev->master_count); 753428d7b3dSmrg if (--dev->master_count == 0) { 754428d7b3dSmrg assert(!hosted()); 755428d7b3dSmrg assert(drmSetMaster(dev->fd) == 0); 756428d7b3dSmrg ret = drmDropMaster(dev->fd); 757428d7b3dSmrg } 758428d7b3dSmrg 759428d7b3dSmrg return ret; 760428d7b3dSmrg} 761428d7b3dSmrg 762428d7b3dSmrgvoid intel_put_device(struct intel_device *dev) 763428d7b3dSmrg{ 764428d7b3dSmrg assert(dev && dev->fd != -1); 765428d7b3dSmrg 766428d7b3dSmrg assert(dev->open_count); 767428d7b3dSmrg if (--dev->open_count) 768428d7b3dSmrg return; 769428d7b3dSmrg 770428d7b3dSmrg assert(!hosted()); 771428d7b3dSmrg xf86GetEntityPrivate(dev->idx, intel_device_key)->ptr = NULL; 772428d7b3dSmrg 773428d7b3dSmrg drmClose(dev->fd); 774428d7b3dSmrg if (dev->render_node != dev->master_node) 775428d7b3dSmrg free(dev->render_node); 776428d7b3dSmrg free(dev->master_node); 777428d7b3dSmrg free(dev); 778428d7b3dSmrg} 779