intel_device.c revision 03b705cf
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 2703b705cfSriastradh#include <assert.h> 2803b705cfSriastradh#include <string.h> 2903b705cfSriastradh#include <unistd.h> 3003b705cfSriastradh#include <fcntl.h> 3103b705cfSriastradh#include <stdlib.h> 3203b705cfSriastradh#include <errno.h> 3303b705cfSriastradh 3403b705cfSriastradh#include <sys/ioctl.h> 3503b705cfSriastradh 3603b705cfSriastradh#include <pciaccess.h> 3703b705cfSriastradh#include <xf86.h> 3803b705cfSriastradh#include <xf86drm.h> 3903b705cfSriastradh#include <xf86drmMode.h> 4003b705cfSriastradh#include <xf86_OSproc.h> 4103b705cfSriastradh#include <i915_drm.h> 4203b705cfSriastradh 4303b705cfSriastradh#include "intel_driver.h" 4403b705cfSriastradh 4503b705cfSriastradhstruct intel_device { 4603b705cfSriastradh char *path; 4703b705cfSriastradh int fd; 4803b705cfSriastradh int open_count; 4903b705cfSriastradh int master_count; 5003b705cfSriastradh}; 5103b705cfSriastradh 5203b705cfSriastradhstatic int intel_device_key = -1; 5303b705cfSriastradh 5403b705cfSriastradhstatic inline struct intel_device *intel_device(ScrnInfoPtr scrn) 5503b705cfSriastradh{ 5603b705cfSriastradh if (scrn->entityList == NULL) 5703b705cfSriastradh return NULL; 5803b705cfSriastradh 5903b705cfSriastradh return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr; 6003b705cfSriastradh} 6103b705cfSriastradh 6203b705cfSriastradhstatic inline void intel_set_device(ScrnInfoPtr scrn, struct intel_device *dev) 6303b705cfSriastradh{ 6403b705cfSriastradh xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr = dev; 6503b705cfSriastradh} 6603b705cfSriastradh 6703b705cfSriastradhstatic Bool is_i915_device(int fd) 6803b705cfSriastradh{ 6903b705cfSriastradh drm_version_t version; 7003b705cfSriastradh char name[5] = ""; 7103b705cfSriastradh 7203b705cfSriastradh memset(&version, 0, sizeof(version)); 7303b705cfSriastradh version.name_len = 4; 7403b705cfSriastradh version.name = name; 7503b705cfSriastradh 7603b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 7703b705cfSriastradh return FALSE; 7803b705cfSriastradh 7903b705cfSriastradh return strcmp("i915", name) == 0; 8003b705cfSriastradh} 8103b705cfSriastradh 8203b705cfSriastradhstatic int __intel_check_device(int fd) 8303b705cfSriastradh{ 8403b705cfSriastradh int ret; 8503b705cfSriastradh 8603b705cfSriastradh /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 8703b705cfSriastradh ret = is_i915_device(fd); 8803b705cfSriastradh if (ret) { 8903b705cfSriastradh struct drm_i915_getparam gp; 9003b705cfSriastradh gp.param = I915_PARAM_HAS_GEM; 9103b705cfSriastradh gp.value = &ret; 9203b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 9303b705cfSriastradh ret = FALSE; 9403b705cfSriastradh } 9503b705cfSriastradh if (ret && !hosted()) { 9603b705cfSriastradh struct drm_mode_card_res res; 9703b705cfSriastradh 9803b705cfSriastradh memset(&res, 0, sizeof(res)); 9903b705cfSriastradh if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 10003b705cfSriastradh ret = FALSE; 10103b705cfSriastradh } 10203b705cfSriastradh 10303b705cfSriastradh return ret; 10403b705cfSriastradh} 10503b705cfSriastradh 10603b705cfSriastradhstatic int fd_set_cloexec(int fd) 10703b705cfSriastradh{ 10803b705cfSriastradh int flags; 10903b705cfSriastradh 11003b705cfSriastradh if (fd == -1) 11103b705cfSriastradh return fd; 11203b705cfSriastradh 11303b705cfSriastradh#ifdef FD_CLOEXEC 11403b705cfSriastradh flags = fcntl(fd, F_GETFD); 11503b705cfSriastradh if (flags != -1) { 11603b705cfSriastradh flags |= FD_CLOEXEC; 11703b705cfSriastradh fcntl(fd, F_SETFD, flags); 11803b705cfSriastradh } 11903b705cfSriastradh#endif 12003b705cfSriastradh 12103b705cfSriastradh return fd; 12203b705cfSriastradh} 12303b705cfSriastradh 12403b705cfSriastradhstatic int __intel_open_device(const struct pci_device *pci, char **path) 12503b705cfSriastradh{ 12603b705cfSriastradh int fd; 12703b705cfSriastradh 12803b705cfSriastradh if (*path == NULL) { 12903b705cfSriastradh char id[20]; 13003b705cfSriastradh int ret; 13103b705cfSriastradh 13203b705cfSriastradh snprintf(id, sizeof(id), 13303b705cfSriastradh "pci:%04x:%02x:%02x.%d", 13403b705cfSriastradh pci->domain, pci->bus, pci->dev, pci->func); 13503b705cfSriastradh 13603b705cfSriastradh ret = drmCheckModesettingSupported(id); 13703b705cfSriastradh if (ret) { 13803b705cfSriastradh if (xf86LoadKernelModule("i915")) 13903b705cfSriastradh ret = drmCheckModesettingSupported(id); 14003b705cfSriastradh if (ret) 14103b705cfSriastradh return -1; 14203b705cfSriastradh /* Be nice to the user and load fbcon too */ 14303b705cfSriastradh (void)xf86LoadKernelModule("fbcon"); 14403b705cfSriastradh } 14503b705cfSriastradh 14603b705cfSriastradh fd = drmOpen(NULL, id); 14703b705cfSriastradh if (fd != -1) { 14803b705cfSriastradh *path = drmGetDeviceNameFromFd(fd); 14903b705cfSriastradh if (*path == NULL) { 15003b705cfSriastradh close(fd); 15103b705cfSriastradh fd = -1; 15203b705cfSriastradh } 15303b705cfSriastradh } 15403b705cfSriastradh } else { 15503b705cfSriastradh#ifdef O_CLOEXEC 15603b705cfSriastradh fd = open(*path, O_RDWR | O_CLOEXEC); 15703b705cfSriastradh#else 15803b705cfSriastradh fd = -1; 15903b705cfSriastradh#endif 16003b705cfSriastradh if (fd == -1) 16103b705cfSriastradh fd = fd_set_cloexec(open(*path, O_RDWR)); 16203b705cfSriastradh } 16303b705cfSriastradh 16403b705cfSriastradh return fd; 16503b705cfSriastradh} 16603b705cfSriastradh 16703b705cfSriastradhint intel_open_device(int entity_num, 16803b705cfSriastradh const struct pci_device *pci, 16903b705cfSriastradh const char *path) 17003b705cfSriastradh{ 17103b705cfSriastradh struct intel_device *dev; 17203b705cfSriastradh char *local_path; 17303b705cfSriastradh int fd; 17403b705cfSriastradh 17503b705cfSriastradh if (intel_device_key == -1) 17603b705cfSriastradh intel_device_key = xf86AllocateEntityPrivateIndex(); 17703b705cfSriastradh if (intel_device_key == -1) 17803b705cfSriastradh return -1; 17903b705cfSriastradh 18003b705cfSriastradh dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr; 18103b705cfSriastradh if (dev) 18203b705cfSriastradh return dev->fd; 18303b705cfSriastradh 18403b705cfSriastradh local_path = path ? strdup(path) : NULL; 18503b705cfSriastradh 18603b705cfSriastradh fd = __intel_open_device(pci, &local_path); 18703b705cfSriastradh if (fd == -1) 18803b705cfSriastradh goto err_path; 18903b705cfSriastradh 19003b705cfSriastradh if (!__intel_check_device(fd)) 19103b705cfSriastradh goto err_close; 19203b705cfSriastradh 19303b705cfSriastradh dev = malloc(sizeof(*dev)); 19403b705cfSriastradh if (dev == NULL) 19503b705cfSriastradh goto err_close; 19603b705cfSriastradh 19703b705cfSriastradh dev->path = local_path; 19803b705cfSriastradh dev->fd = fd; 19903b705cfSriastradh dev->open_count = 0; 20003b705cfSriastradh dev->master_count = 0; 20103b705cfSriastradh 20203b705cfSriastradh /* If hosted under a system compositor, just pretend to be master */ 20303b705cfSriastradh if (hosted()) { 20403b705cfSriastradh dev->open_count++; 20503b705cfSriastradh dev->master_count++; 20603b705cfSriastradh } 20703b705cfSriastradh 20803b705cfSriastradh xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = dev; 20903b705cfSriastradh 21003b705cfSriastradh return fd; 21103b705cfSriastradh 21203b705cfSriastradherr_close: 21303b705cfSriastradh close(fd); 21403b705cfSriastradherr_path: 21503b705cfSriastradh free(local_path); 21603b705cfSriastradh return -1; 21703b705cfSriastradh} 21803b705cfSriastradh 21903b705cfSriastradhint intel_get_device(ScrnInfoPtr scrn) 22003b705cfSriastradh{ 22103b705cfSriastradh struct intel_device *dev; 22203b705cfSriastradh int ret; 22303b705cfSriastradh 22403b705cfSriastradh dev = intel_device(scrn); 22503b705cfSriastradh assert(dev && dev->fd != -1); 22603b705cfSriastradh 22703b705cfSriastradh if (dev->open_count++ == 0) { 22803b705cfSriastradh drmSetVersion sv; 22903b705cfSriastradh int retry = 2000; 23003b705cfSriastradh 23103b705cfSriastradh assert(!hosted()); 23203b705cfSriastradh 23303b705cfSriastradh /* Check that what we opened was a master or a 23403b705cfSriastradh * master-capable FD, by setting the version of the 23503b705cfSriastradh * interface we'll use to talk to it. 23603b705cfSriastradh */ 23703b705cfSriastradh do { 23803b705cfSriastradh sv.drm_di_major = 1; 23903b705cfSriastradh sv.drm_di_minor = 1; 24003b705cfSriastradh sv.drm_dd_major = -1; 24103b705cfSriastradh sv.drm_dd_minor = -1; 24203b705cfSriastradh ret = drmIoctl(dev->fd, DRM_IOCTL_SET_VERSION, &sv); 24303b705cfSriastradh if (ret == 0) 24403b705cfSriastradh break; 24503b705cfSriastradh 24603b705cfSriastradh usleep(1000); 24703b705cfSriastradh } while (--retry); 24803b705cfSriastradh if (ret != 0) { 24903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 25003b705cfSriastradh "[drm] failed to set drm interface version: %s [%d].\n", 25103b705cfSriastradh strerror(errno), errno); 25203b705cfSriastradh dev->open_count--; 25303b705cfSriastradh return -1; 25403b705cfSriastradh } 25503b705cfSriastradh } 25603b705cfSriastradh 25703b705cfSriastradh return dev->fd; 25803b705cfSriastradh} 25903b705cfSriastradh 26003b705cfSriastradhconst char *intel_get_device_name(ScrnInfoPtr scrn) 26103b705cfSriastradh{ 26203b705cfSriastradh struct intel_device *dev = intel_device(scrn); 26303b705cfSriastradh assert(dev && dev->path); 26403b705cfSriastradh return dev->path; 26503b705cfSriastradh} 26603b705cfSriastradh 26703b705cfSriastradhint intel_get_master(ScrnInfoPtr scrn) 26803b705cfSriastradh{ 26903b705cfSriastradh struct intel_device *dev = intel_device(scrn); 27003b705cfSriastradh int ret; 27103b705cfSriastradh 27203b705cfSriastradh assert(dev && dev->fd != -1); 27303b705cfSriastradh 27403b705cfSriastradh ret = 0; 27503b705cfSriastradh if (dev->master_count++ == 0) { 27603b705cfSriastradh int retry = 2000; 27703b705cfSriastradh 27803b705cfSriastradh assert(!hosted()); 27903b705cfSriastradh do { 28003b705cfSriastradh ret = drmSetMaster(dev->fd); 28103b705cfSriastradh if (ret == 0) 28203b705cfSriastradh break; 28303b705cfSriastradh usleep(1000); 28403b705cfSriastradh } while (--retry); 28503b705cfSriastradh } 28603b705cfSriastradh 28703b705cfSriastradh return ret; 28803b705cfSriastradh} 28903b705cfSriastradh 29003b705cfSriastradhint intel_put_master(ScrnInfoPtr scrn) 29103b705cfSriastradh{ 29203b705cfSriastradh struct intel_device *dev = intel_device(scrn); 29303b705cfSriastradh int ret; 29403b705cfSriastradh 29503b705cfSriastradh assert(dev && dev->fd != -1); 29603b705cfSriastradh 29703b705cfSriastradh ret = 0; 29803b705cfSriastradh assert(dev->master_count); 29903b705cfSriastradh if (--dev->master_count == 0) { 30003b705cfSriastradh assert(!hosted()); 30103b705cfSriastradh assert(drmSetMaster(dev->fd) == 0); 30203b705cfSriastradh ret = drmDropMaster(dev->fd); 30303b705cfSriastradh } 30403b705cfSriastradh 30503b705cfSriastradh return ret; 30603b705cfSriastradh} 30703b705cfSriastradh 30803b705cfSriastradhvoid __intel_uxa_release_device(ScrnInfoPtr scrn) 30903b705cfSriastradh{ 31003b705cfSriastradh struct intel_device *dev = intel_device(scrn); 31103b705cfSriastradh if (dev && dev->open_count == 0) { 31203b705cfSriastradh intel_set_device(scrn, NULL); 31303b705cfSriastradh 31403b705cfSriastradh drmClose(dev->fd); 31503b705cfSriastradh free(dev->path); 31603b705cfSriastradh free(dev); 31703b705cfSriastradh } 31803b705cfSriastradh} 31903b705cfSriastradh 32003b705cfSriastradhvoid intel_put_device(ScrnInfoPtr scrn) 32103b705cfSriastradh{ 32203b705cfSriastradh struct intel_device *dev = intel_device(scrn); 32303b705cfSriastradh 32403b705cfSriastradh assert(dev && dev->fd != -1); 32503b705cfSriastradh 32603b705cfSriastradh assert(dev->open_count); 32703b705cfSriastradh if (--dev->open_count) 32803b705cfSriastradh return; 32903b705cfSriastradh 33003b705cfSriastradh assert(!hosted()); 33103b705cfSriastradh intel_set_device(scrn, NULL); 33203b705cfSriastradh 33303b705cfSriastradh drmClose(dev->fd); 33403b705cfSriastradh free(dev->path); 33503b705cfSriastradh free(dev); 33603b705cfSriastradh} 337