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