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