intel_device.c revision 42542f5f
1/*************************************************************************** 2 3 Copyright 2013 Intel Corporation. All Rights Reserved. 4 5 Permission is hereby granted, free of charge, to any person obtaining a 6 copy of this software and associated documentation files (the 7 "Software"), to deal in the Software without restriction, including 8 without limitation the rights to use, copy, modify, merge, publish, 9 distribute, sub license, and/or sell copies of the Software, and to 10 permit persons to whom the Software is furnished to do so, subject to 11 the following conditions: 12 13 The above copyright notice and this permission notice (including the 14 next paragraph) shall be included in all copies or substantial portions 15 of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 23 THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 **************************************************************************/ 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#include <sys/types.h> 32#include <sys/stat.h> 33#include <assert.h> 34#include <string.h> 35#include <unistd.h> 36#include <fcntl.h> 37#include <stdlib.h> 38#include <dirent.h> 39#include <errno.h> 40 41#include <pciaccess.h> 42 43#include <xorg-server.h> 44#include <xf86.h> 45#include <xf86drm.h> 46#include <xf86drmMode.h> 47#include <xf86_OSproc.h> 48#include <i915_drm.h> 49 50#ifdef XSERVER_PLATFORM_BUS 51#include <xf86platformBus.h> 52#endif 53 54#ifdef HAVE_VALGRIND 55#include <valgrind.h> 56#include <memcheck.h> 57#define VG(x) x 58#else 59#define VG(x) 60#endif 61 62#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) 63 64#include "intel_driver.h" 65#include "fd.h" 66 67struct intel_device { 68 char *master_node; 69 char *render_node; 70 int fd; 71 int open_count; 72 int master_count; 73}; 74 75static int intel_device_key = -1; 76 77static int dump_file(ScrnInfoPtr scrn, const char *path) 78{ 79 FILE *file; 80 size_t len = 0; 81 char *line = NULL; 82 83 file = fopen(path, "r"); 84 if (file == NULL) 85 return 0; 86 87 xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] Contents of '%s':\n", path); 88 while (getline(&line, &len, file) != -1) 89 xf86DrvMsg(scrn->scrnIndex, X_INFO, "[drm] %s", line); 90 91 free(line); 92 fclose(file); 93 return 1; 94} 95 96static int __find_debugfs(void) 97{ 98 int i; 99 100 for (i = 0; i < DRM_MAX_MINOR; i++) { 101 char path[80]; 102 103 sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 104 if (access(path, R_OK) == 0) 105 return i; 106 107 sprintf(path, "/debug/dri/%d/i915_wedged", i); 108 if (access(path, R_OK) == 0) 109 return i; 110 } 111 112 return -1; 113} 114 115static int drm_get_minor(int fd) 116{ 117 struct stat st; 118 119 if (fstat(fd, &st)) 120 return __find_debugfs(); 121 122 if (!S_ISCHR(st.st_mode)) 123 return __find_debugfs(); 124 125 return st.st_rdev & 0x63; 126} 127 128#if __linux__ 129#include <sys/mount.h> 130 131static void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) 132{ 133 char path[80]; 134 int minor; 135 136 minor = drm_get_minor(fd); 137 if (minor < 0) 138 return; 139 140 sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 141 if (dump_file(scrn, path)) 142 return; 143 144 sprintf(path, "/debug/dri/%d/%s", minor, name); 145 if (dump_file(scrn, path)) 146 return; 147 148 if (mount("X-debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0) { 149 sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 150 dump_file(scrn, path); 151 umount("X-debug"); 152 return; 153 } 154} 155#else 156static void dump_debugfs(ScrnInfoPtr scrn, int fd, const char *name) { } 157#endif 158 159static void dump_clients_info(ScrnInfoPtr scrn, int fd) 160{ 161 dump_debugfs(scrn, fd, "clients"); 162} 163 164static int __intel_get_device_id(int fd) 165{ 166 struct drm_i915_getparam gp; 167 int devid = 0; 168 169 VG_CLEAR(gp); 170 gp.param = I915_PARAM_CHIPSET_ID; 171 gp.value = &devid; 172 173 if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 174 return 0; 175 176 return devid; 177} 178 179int intel_entity_get_devid(int idx) 180{ 181 struct intel_device *dev; 182 183 dev = xf86GetEntityPrivate(idx, intel_device_key)->ptr; 184 if (dev == NULL) 185 return 0; 186 187 return __intel_get_device_id(dev->fd); 188} 189 190static inline struct intel_device *intel_device(ScrnInfoPtr scrn) 191{ 192 if (scrn->entityList == NULL) 193 return NULL; 194 195 return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 196} 197 198static inline void intel_set_device(ScrnInfoPtr scrn, struct intel_device *dev) 199{ 200 xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr = dev; 201} 202 203static int is_i915_device(int fd) 204{ 205 drm_version_t version; 206 char name[5] = ""; 207 208 memset(&version, 0, sizeof(version)); 209 version.name_len = 4; 210 version.name = name; 211 212 if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 213 return 0; 214 215 return strcmp("i915", name) == 0; 216} 217 218static int is_i915_gem(int fd) 219{ 220 int ret = is_i915_device(fd); 221 222 if (ret) { 223 struct drm_i915_getparam gp; 224 225 VG_CLEAR(gp); 226 gp.param = I915_PARAM_HAS_GEM; 227 gp.value = &ret; 228 229 if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 230 ret = 0; 231 } 232 233 return ret; 234} 235 236static int __intel_check_device(int fd) 237{ 238 int ret; 239 240 /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 241 ret = is_i915_gem(fd); 242 if (ret && !hosted()) { 243 struct drm_mode_card_res res; 244 245 memset(&res, 0, sizeof(res)); 246 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 247 ret = 0; 248 } 249 250 return ret; 251} 252 253static int open_cloexec(const char *path) 254{ 255 struct stat st; 256 int loop = 1000; 257 int fd; 258 259 /* No file? Assume the driver is loading slowly */ 260 while (stat(path, &st) == -1 && errno == ENOENT && --loop) 261 usleep(50000); 262 263 if (loop != 1000) 264 ErrorF("intel: waited %d ms for '%s' to appear\n", 265 (1000 - loop) * 50, path); 266 267 fd = -1; 268#ifdef O_CLOEXEC 269 fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC); 270#endif 271 if (fd == -1) 272 fd = fd_set_cloexec(open(path, O_RDWR | O_NONBLOCK)); 273 274 return fd; 275} 276 277#ifdef __linux__ 278static int __intel_open_device__major_minor(int _major, int _minor) 279{ 280 char path[256]; 281 DIR *dir; 282 struct dirent *de; 283 int base, fd = -1; 284 285 base = sprintf(path, "/dev/dri/"); 286 287 dir = opendir(path); 288 if (dir == NULL) 289 return -1; 290 291 while ((de = readdir(dir)) != NULL) { 292 struct stat st; 293 294 if (*de->d_name == '.') 295 continue; 296 297 sprintf(path + base, "%s", de->d_name); 298 if (stat(path, &st) == 0 && 299 major(st.st_rdev) == _major && 300 minor(st.st_rdev) == _minor) { 301 fd = open_cloexec(path); 302 break; 303 } 304 } 305 306 closedir(dir); 307 308 return fd; 309} 310 311static int __intel_open_device__pci(const struct pci_device *pci) 312{ 313 struct stat st; 314 char path[256]; 315 DIR *dir; 316 struct dirent *de; 317 int base; 318 int fd; 319 320 /* Look up the major:minor for the drm device through sysfs. 321 * First we need to check that sysfs is available, then 322 * check that we have loaded our driver. When we are happy 323 * that our KMS module is loaded, we can then search for our 324 * device node. We make the assumption that it uses the same 325 * name, but after that we read the major:minor assigned to us 326 * and search for a matching entry in /dev. 327 */ 328 329 base = sprintf(path, 330 "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 331 pci->domain, pci->bus, pci->dev, pci->func); 332 if (stat(path, &st)) 333 return -1; 334 335 sprintf(path + base, "drm"); 336 dir = opendir(path); 337 if (dir == NULL) { 338 int loop = 0; 339 340 sprintf(path + base, "driver"); 341 if (stat(path, &st)) { 342 if (xf86LoadKernelModule("i915")) 343 return -1; 344 (void)xf86LoadKernelModule("fbcon"); 345 } 346 347 sprintf(path + base, "drm"); 348 while ((dir = opendir(path)) == NULL && loop++ < 100) 349 usleep(20000); 350 351 ErrorF("intel: waited %d ms for i915.ko driver to load\n", loop * 20000 / 1000); 352 353 if (dir == NULL) 354 return -1; 355 } 356 357 fd = -1; 358 while ((de = readdir(dir)) != NULL) { 359 if (*de->d_name == '.') 360 continue; 361 362 if (strncmp(de->d_name, "card", 4) == 0) { 363 sprintf(path + base + 4, "/dev/dri/%s", de->d_name); 364 fd = open_cloexec(path + base + 4); 365 if (fd != -1) 366 break; 367 368 sprintf(path + base + 3, "/%s/dev", de->d_name); 369 fd = open(path, O_RDONLY); 370 if (fd == -1) 371 break; 372 373 base = read(fd, path, sizeof(path) - 1); 374 close(fd); 375 376 fd = -1; 377 if (base > 0) { 378 int major, minor; 379 path[base] = '\0'; 380 if (sscanf(path, "%d:%d", &major, &minor) == 2) 381 fd = __intel_open_device__major_minor(major, minor); 382 } 383 break; 384 } 385 } 386 closedir(dir); 387 388 return fd; 389} 390#else 391static int __intel_open_device__pci(const struct pci_device *pci) { return -1; } 392#endif 393 394static int __intel_open_device__legacy(const struct pci_device *pci) 395{ 396 char id[20]; 397 int ret; 398 399 snprintf(id, sizeof(id), 400 "pci:%04x:%02x:%02x.%d", 401 pci->domain, pci->bus, pci->dev, pci->func); 402 403 ret = drmCheckModesettingSupported(id); 404 if (ret) { 405 if (xf86LoadKernelModule("i915")) 406 ret = drmCheckModesettingSupported(id); 407 if (ret) 408 return -1; 409 /* Be nice to the user and load fbcon too */ 410 (void)xf86LoadKernelModule("fbcon"); 411 } 412 413 return fd_set_nonblock(drmOpen(NULL, id)); 414} 415 416static int __intel_open_device(const struct pci_device *pci, const char *path) 417{ 418 int fd; 419 420 if (path == NULL) { 421 if (pci == NULL) 422 return -1; 423 424 fd = __intel_open_device__pci(pci); 425 if (fd == -1) 426 fd = __intel_open_device__legacy(pci); 427 } else 428 fd = open_cloexec(path); 429 430 return fd; 431} 432 433static char *find_master_node(int fd) 434{ 435 struct stat st, master; 436 char buf[128]; 437 438 if (fstat(fd, &st)) 439 return NULL; 440 441 if (!S_ISCHR(st.st_mode)) 442 return NULL; 443 444 sprintf(buf, "/dev/dri/card%d", (int)(st.st_rdev & 0x7f)); 445 if (stat(buf, &master) == 0 && 446 st.st_mode == master.st_mode && 447 (st.st_rdev & 0x7f) == master.st_rdev) 448 return strdup(buf); 449 450 /* Fallback to iterating over the usual suspects */ 451 return drmGetDeviceNameFromFd(fd); 452} 453 454static int is_render_node(int fd, struct stat *st) 455{ 456 if (fstat(fd, st)) 457 return 0; 458 459 if (!S_ISCHR(st->st_mode)) 460 return 0; 461 462 return st->st_rdev & 0x80; 463} 464 465static char *find_render_node(int fd) 466{ 467#if defined(USE_RENDERNODE) 468 struct stat master, render; 469 char buf[128]; 470 471 /* Are we a render-node ourselves? */ 472 if (is_render_node(fd, &master)) 473 return NULL; 474 475 sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf)); 476 if (stat(buf, &render) == 0 && 477 master.st_mode == render.st_mode && 478 render.st_rdev == ((master.st_rdev | 0x80) & 0xbf)) 479 return strdup(buf); 480#endif 481 482 return NULL; 483} 484 485#if defined(ODEV_ATTRIB_PATH) 486static char *get_path(struct xf86_platform_device *dev) 487{ 488 const char *path; 489 490 if (dev == NULL) 491 return NULL; 492 493 path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH); 494 if (path == NULL) 495 return NULL; 496 497 return strdup(path); 498} 499 500#else 501 502static char *get_path(struct xf86_platform_device *dev) 503{ 504 return NULL; 505} 506#endif 507 508 509#if defined(ODEV_ATTRIB_FD) 510static int get_fd(struct xf86_platform_device *dev) 511{ 512 if (dev == NULL) 513 return -1; 514 515 return xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1); 516} 517 518#else 519 520static int get_fd(struct xf86_platform_device *dev) 521{ 522 return -1; 523} 524#endif 525 526static int is_master(int fd) 527{ 528 drmSetVersion sv; 529 530 sv.drm_di_major = 1; 531 sv.drm_di_minor = 1; 532 sv.drm_dd_major = -1; 533 sv.drm_dd_minor = -1; 534 535 return drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv) == 0; 536} 537 538int intel_open_device(int entity_num, 539 const struct pci_device *pci, 540 struct xf86_platform_device *platform) 541{ 542 struct intel_device *dev; 543 char *path; 544 int fd, master_count; 545 546 if (intel_device_key == -1) 547 intel_device_key = xf86AllocateEntityPrivateIndex(); 548 if (intel_device_key == -1) 549 return -1; 550 551 dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 552 if (dev) 553 return dev->fd; 554 555 path = get_path(platform); 556 557 master_count = 1; /* DRM_MASTER is managed by Xserver */ 558 fd = get_fd(platform); 559 if (fd == -1) { 560 fd = __intel_open_device(pci, path); 561 if (fd == -1) 562 goto err_path; 563 564 master_count = 0; 565 } 566 567 if (path == NULL) { 568 path = find_master_node(fd); 569 if (path == NULL) 570 goto err_close; 571 } 572 573 if (!__intel_check_device(fd)) 574 goto err_close; 575 576 dev = malloc(sizeof(*dev)); 577 if (dev == NULL) 578 goto err_close; 579 580 /* If hosted under a system compositor, just pretend to be master */ 581 if (hosted()) 582 master_count++; 583 584 /* Non-root user holding MASTER, don't let go */ 585 if (geteuid() && is_master(fd)) 586 master_count++; 587 588 dev->fd = fd; 589 dev->open_count = master_count; 590 dev->master_count = master_count; 591 dev->master_node = path; 592 dev->render_node = find_render_node(fd); 593 if (dev->render_node == NULL) 594 dev->render_node = dev->master_node; 595 596 xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 597 598 return fd; 599 600err_close: 601 if (master_count == 0) /* Don't close server-fds */ 602 close(fd); 603err_path: 604 free(path); 605 return -1; 606} 607 608int __intel_peek_fd(ScrnInfoPtr scrn) 609{ 610 struct intel_device *dev; 611 612 dev = intel_device(scrn); 613 assert(dev && dev->fd != -1); 614 615 return dev->fd; 616} 617 618int intel_has_render_node(ScrnInfoPtr scrn) 619{ 620 struct intel_device *dev; 621 struct stat st; 622 623 dev = intel_device(scrn); 624 assert(dev && dev->fd != -1); 625 626 return is_render_node(dev->fd, &st); 627} 628 629int intel_get_device(ScrnInfoPtr scrn) 630{ 631 struct intel_device *dev; 632 int ret; 633 634 dev = intel_device(scrn); 635 assert(dev && dev->fd != -1); 636 637 if (dev->open_count++ == 0) { 638 drmSetVersion sv; 639 int retry = 2000; 640 641 assert(!hosted()); 642 643 /* Check that what we opened was a master or a 644 * master-capable FD, by setting the version of the 645 * interface we'll use to talk to it. 646 */ 647 do { 648 sv.drm_di_major = 1; 649 sv.drm_di_minor = 1; 650 sv.drm_dd_major = -1; 651 sv.drm_dd_minor = -1; 652 ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 653 if (ret == 0) 654 break; 655 656 usleep(1000); 657 } while (--retry); 658 if (ret != 0) { 659 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 660 "[drm] failed to set drm interface version: %s [%d].\n", 661 strerror(errno), errno); 662 dump_clients_info(scrn, dev->fd); 663 dev->open_count--; 664 return -1; 665 } 666 } 667 668 return dev->fd; 669} 670 671const char *intel_get_client_name(ScrnInfoPtr scrn) 672{ 673 struct intel_device *dev = intel_device(scrn); 674 assert(dev && dev->render_node); 675 return dev->render_node; 676} 677 678static int authorise(struct intel_device *dev, int fd) 679{ 680 struct stat st; 681 drm_magic_t magic; 682 683 if (is_render_node(fd, &st)) /* restricted authority, do not elevate */ 684 return 1; 685 686 return drmGetMagic(fd, &magic) == 0 && drmAuthMagic(dev->fd, magic) == 0; 687} 688 689int intel_get_client_fd(ScrnInfoPtr scrn) 690{ 691 struct intel_device *dev; 692 int fd = -1; 693 694 dev = intel_device(scrn); 695 assert(dev); 696 assert(dev->fd != -1); 697 assert(dev->render_node); 698 699#ifdef O_CLOEXEC 700 fd = open(dev->render_node, O_RDWR | O_CLOEXEC); 701#endif 702 if (fd < 0) 703 fd = fd_set_cloexec(open(dev->render_node, O_RDWR)); 704 if (fd < 0) 705 return -BadAlloc; 706 707 if (!authorise(dev, fd)) { 708 close(fd); 709 return -BadMatch; 710 } 711 712 assert(is_i915_gem(fd)); 713 714 return fd; 715} 716 717int intel_get_device_id(ScrnInfoPtr scrn) 718{ 719 struct intel_device *dev = intel_device(scrn); 720 assert(dev && dev->fd != -1); 721 return __intel_get_device_id(dev->fd); 722} 723 724int intel_get_master(ScrnInfoPtr scrn) 725{ 726 struct intel_device *dev = intel_device(scrn); 727 int ret; 728 729 assert(dev && dev->fd != -1); 730 731 ret = 0; 732 if (dev->master_count++ == 0) { 733 int retry = 2000; 734 735 assert(!hosted()); 736 do { 737 ret = drmSetMaster(dev->fd); 738 if (ret == 0) 739 break; 740 usleep(1000); 741 } while (--retry); 742 } 743 744 return ret; 745} 746 747int intel_put_master(ScrnInfoPtr scrn) 748{ 749 struct intel_device *dev = intel_device(scrn); 750 int ret; 751 752 assert(dev && dev->fd != -1); 753 754 ret = 0; 755 assert(dev->master_count); 756 if (--dev->master_count == 0) { 757 assert(!hosted()); 758 assert(drmSetMaster(dev->fd) == 0); 759 ret = drmDropMaster(dev->fd); 760 } 761 762 return ret; 763} 764 765void intel_put_device(ScrnInfoPtr scrn) 766{ 767 struct intel_device *dev = intel_device(scrn); 768 769 assert(dev && dev->fd != -1); 770 771 assert(dev->open_count); 772 if (--dev->open_count) 773 return; 774 775 assert(!hosted()); 776 intel_set_device(scrn, NULL); 777 778 drmClose(dev->fd); 779 if (dev->render_node != dev->master_node) 780 free(dev->render_node); 781 free(dev->master_node); 782 free(dev); 783} 784