1 /*
2  * Copyright © 2007, 2011, 2013 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Daniel Vetter <daniel.vetter@ffwll.ch>
26  *
27  */
28 
29 #ifdef HAVE_LIBGEN_H
30 #include <libgen.h>
31 #endif
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #include <string.h>
37 #include <sys/mman.h>
38 #include <signal.h>
39 #include <pciaccess.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <sys/wait.h>
43 #include <sys/types.h>
44 #include <sys/syscall.h>
45 #include <sys/utsname.h>
46 #include <termios.h>
47 #include <pthread.h>
48 
49 #include "drmtest.h"
50 #include "i915_drm.h"
51 #include "intel_chipset.h"
52 #include "intel_io.h"
53 #include "igt_debugfs.h"
54 #include "igt_device.h"
55 #include "igt_gt.h"
56 #include "igt_kmod.h"
57 #include "igt_sysfs.h"
58 #include "version.h"
59 #include "config.h"
60 #include "intel_reg.h"
61 #include "ioctl_wrappers.h"
62 #include "igt_dummyload.h"
63 
64 /**
65  * SECTION:drmtest
66  * @short_description: Base library for drm tests and tools
67  * @title: drmtest
68  * @include: igt.h
69  *
70  * This library contains the basic support for writing tests, with the most
71  * important part being the helper function to open drm device nodes.
72  *
73  * But there's also a bit of other assorted stuff here.
74  *
75  * Note that this library's header pulls in the [i-g-t core](igt-gpu-tools-i-g-t-core.html)
76  * and [batchbuffer](igt-gpu-tools-intel-batchbuffer.html) libraries as dependencies.
77  */
78 
__get_drm_device_name(int fd,char * name,int name_size)79 static int __get_drm_device_name(int fd, char *name, int name_size)
80 {
81 	drm_version_t version;
82 
83 	memset(&version, 0, sizeof(version));
84 	version.name_len = name_size;
85 	version.name = name;
86 
87 	if (!drmIoctl(fd, DRM_IOCTL_VERSION, &version)){
88 		return 0;
89 	}
90 
91 	return -1;
92 }
93 
__is_device(int fd,const char * expect)94 static bool __is_device(int fd, const char *expect)
95 {
96 	char name[12] = "";
97 
98 	if (__get_drm_device_name(fd, name, sizeof(name) - 1))
99 		return false;
100 
101 	return strcmp(expect, name) == 0;
102 }
103 
is_amdgpu_device(int fd)104 bool is_amdgpu_device(int fd)
105 {
106 	return __is_device(fd, "amdgpu");
107 }
108 
is_i915_device(int fd)109 bool is_i915_device(int fd)
110 {
111 	return __is_device(fd, "i915");
112 }
113 
is_vc4_device(int fd)114 bool is_vc4_device(int fd)
115 {
116 	return __is_device(fd, "vc4");
117 }
118 
has_known_intel_chipset(int fd)119 static bool has_known_intel_chipset(int fd)
120 {
121 	struct drm_i915_getparam gp;
122 	int devid = 0;
123 
124 	memset(&gp, 0, sizeof(gp));
125 	gp.param = I915_PARAM_CHIPSET_ID;
126 	gp.value = &devid;
127 
128 	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
129 		return false;
130 
131 	if (!intel_gen(devid))
132 		return false;
133 
134 	return true;
135 }
136 
137 static char _forced_driver[16] = "";
138 
139 /**
140  * __set_forced_driver:
141  * @name: name of driver to forcibly use
142  *
143  * Set the name of a driver to use when calling #drm_open_driver with
144  * the #DRIVER_ANY flag.
145  */
__set_forced_driver(const char * name)146 void __set_forced_driver(const char *name)
147 {
148 	if (!name) {
149 		igt_warn("No driver specified, keep default behaviour\n");
150 		return;
151 	}
152 
153 	strncpy(_forced_driver, name, sizeof(_forced_driver) - 1);
154 }
155 
forced_driver(void)156 static const char *forced_driver(void)
157 {
158 	if (_forced_driver[0])
159 		return _forced_driver;
160 
161 	return NULL;
162 }
163 
164 #define LOCAL_I915_EXEC_VEBOX	(4 << 0)
165 /**
166  * gem_quiescent_gpu:
167  * @fd: open i915 drm file descriptor
168  *
169  * Ensure the gpu is idle by launching a nop execbuf and stalling for it. This
170  * is automatically run when opening a drm device node and is also installed as
171  * an exit handler to have the best assurance that the test is run in a pristine
172  * and controlled environment.
173  *
174  * This function simply allows tests to make additional calls in-between, if so
175  * desired.
176  */
gem_quiescent_gpu(int fd)177 void gem_quiescent_gpu(int fd)
178 {
179 	igt_terminate_spins();
180 
181 	igt_drop_caches_set(fd,
182 			    DROP_ACTIVE | DROP_RETIRE | DROP_IDLE | DROP_FREED);
183 }
184 
modprobe(const char * driver)185 static int modprobe(const char *driver)
186 {
187 	return igt_kmod_load(driver, "");
188 }
189 
modprobe_i915(const char * name)190 static void modprobe_i915(const char *name)
191 {
192 	/* When loading i915, we also want to load snd-hda et al */
193 	igt_i915_driver_load(NULL);
194 }
195 
196 static const struct module {
197 	unsigned int bit;
198 	const char *module;
199 	void (*modprobe)(const char *name);
200 } modules[] = {
201 	{ DRIVER_AMDGPU, "amdgpu" },
202 	{ DRIVER_INTEL, "i915", modprobe_i915 },
203 	{ DRIVER_PANFROST, "panfrost" },
204 	{ DRIVER_V3D, "v3d" },
205 	{ DRIVER_VC4, "vc4" },
206 	{ DRIVER_VGEM, "vgem" },
207 	{}
208 };
209 
open_device(const char * name,unsigned int chipset)210 static int open_device(const char *name, unsigned int chipset)
211 {
212 	const char *forced;
213 	char dev_name[16] = "";
214 	int chip = DRIVER_ANY;
215 	int fd;
216 
217 	fd = open(name, O_RDWR);
218 	if (fd == -1)
219 		return -1;
220 
221 	if (__get_drm_device_name(fd, dev_name, sizeof(dev_name) - 1) == -1)
222 		goto err;
223 
224 	forced = forced_driver();
225 	if (forced && chipset == DRIVER_ANY && strcmp(forced, dev_name))
226 		goto err;
227 
228 	for (int start = 0, end = ARRAY_SIZE(modules) - 1; start < end; ){
229 		int mid = start + (end - start) / 2;
230 		int ret = strcmp(modules[mid].module, dev_name);
231 		if (ret < 0) {
232 			start = mid + 1;
233 		} else if (ret > 0) {
234 			end = mid;
235 		} else {
236 			chip = modules[mid].bit;
237 			break;
238 		}
239 	}
240 	if ((chipset & chip) == chip)
241 		return fd;
242 
243 err:
244 	close(fd);
245 	return -1;
246 }
247 
__search_and_open(const char * base,int offset,unsigned int chipset)248 static int __search_and_open(const char *base, int offset, unsigned int chipset)
249 {
250 	const char *forced;
251 
252 	forced = forced_driver();
253 	if (forced)
254 		igt_info("Force option used: Using driver %s\n", forced);
255 
256 	for (int i = 0; i < 16; i++) {
257 		char name[80];
258 		int fd;
259 
260 		sprintf(name, "%s%u", base, i + offset);
261 		fd = open_device(name, chipset);
262 		if (fd != -1)
263 			return fd;
264 	}
265 
266 	return -1;
267 }
268 
__open_driver(const char * base,int offset,unsigned int chipset)269 static int __open_driver(const char *base, int offset, unsigned int chipset)
270 {
271 	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
272 	int fd;
273 
274 	fd = __search_and_open(base, offset, chipset);
275 	if (fd != -1)
276 		return fd;
277 
278 	pthread_mutex_lock(&mutex);
279 	for (const struct module *m = modules; m->module; m++) {
280 		if (chipset & m->bit) {
281 			if (m->modprobe)
282 				m->modprobe(m->module);
283 			else
284 				modprobe(m->module);
285 		}
286 	}
287 	pthread_mutex_unlock(&mutex);
288 
289 	return __search_and_open(base, offset, chipset);
290 }
291 
292 /**
293  * __drm_open_driver:
294  * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
295  *
296  * Open the first DRM device we can find, searching up to 16 device nodes
297  *
298  * Returns:
299  * An open DRM fd or -1 on error
300  */
__drm_open_driver(int chipset)301 int __drm_open_driver(int chipset)
302 {
303 	return __open_driver("/dev/dri/card", 0, chipset);
304 }
305 
__drm_open_driver_render(int chipset)306 static int __drm_open_driver_render(int chipset)
307 {
308 	return __open_driver("/dev/dri/renderD", 128, chipset);
309 }
310 
311 static int at_exit_drm_fd = -1;
312 static int at_exit_drm_render_fd = -1;
313 
__cancel_work_at_exit(int fd)314 static void __cancel_work_at_exit(int fd)
315 {
316 	igt_terminate_spins(); /* for older kernels */
317 
318 	igt_sysfs_set_parameter(fd, "reset", "%x", -1u /* any method */);
319 	igt_drop_caches_set(fd,
320 			    /* cancel everything */
321 			    DROP_RESET_ACTIVE | DROP_RESET_SEQNO |
322 			    /* cleanup */
323 			    DROP_ACTIVE | DROP_RETIRE | DROP_IDLE | DROP_FREED);
324 }
325 
cancel_work_at_exit(int sig)326 static void cancel_work_at_exit(int sig)
327 {
328 	if (at_exit_drm_fd < 0)
329 		return;
330 
331 	__cancel_work_at_exit(at_exit_drm_fd);
332 
333 	close(at_exit_drm_fd);
334 	at_exit_drm_fd = -1;
335 }
336 
cancel_work_at_exit_render(int sig)337 static void cancel_work_at_exit_render(int sig)
338 {
339 	if (at_exit_drm_render_fd < 0)
340 		return;
341 
342 	__cancel_work_at_exit(at_exit_drm_render_fd);
343 
344 	close(at_exit_drm_render_fd);
345 	at_exit_drm_render_fd = -1;
346 }
347 
chipset_to_str(int chipset)348 static const char *chipset_to_str(int chipset)
349 {
350 	switch (chipset) {
351 	case DRIVER_INTEL:
352 		return "intel";
353 	case DRIVER_V3D:
354 		return "v3d";
355 	case DRIVER_VC4:
356 		return "vc4";
357 	case DRIVER_VGEM:
358 		return "vgem";
359 	case DRIVER_AMDGPU:
360 		return "amdgpu";
361 	case DRIVER_PANFROST:
362 		return "panfrost";
363 	case DRIVER_ANY:
364 		return "any";
365 	default:
366 		return "other";
367 	}
368 }
369 
370 /**
371  * drm_open_driver:
372  * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
373  *
374  * Open a drm legacy device node. This function always returns a valid
375  * file descriptor.
376  *
377  * Returns: a drm file descriptor
378  */
drm_open_driver(int chipset)379 int drm_open_driver(int chipset)
380 {
381 	static int open_count;
382 	int fd;
383 
384 	fd = __drm_open_driver(chipset);
385 	igt_skip_on_f(fd<0, "No known gpu found for chipset flags 0x%u (%s)\n",
386 		      chipset, chipset_to_str(chipset));
387 
388 	/* For i915, at least, we ensure that the driver is idle before
389 	 * starting a test and we install an exit handler to wait until
390 	 * idle before quitting.
391 	 */
392 	if (is_i915_device(fd)) {
393 		if (__sync_fetch_and_add(&open_count, 1) == 0) {
394 			gem_quiescent_gpu(fd);
395 
396 			at_exit_drm_fd = __drm_open_driver(chipset);
397 			igt_install_exit_handler(cancel_work_at_exit);
398 		}
399 	}
400 
401 	return fd;
402 }
403 
404 /**
405  * drm_open_driver_master:
406  * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
407  *
408  * Open a drm legacy device node and ensure that it is drm master.
409  *
410  * Returns:
411  * The drm file descriptor or -1 on error
412  */
drm_open_driver_master(int chipset)413 int drm_open_driver_master(int chipset)
414 {
415 	int fd = drm_open_driver(chipset);
416 
417 	igt_device_set_master(fd);
418 
419 	return fd;
420 }
421 
422 /**
423  * drm_open_driver_render:
424  * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
425  *
426  * Open a drm render device node.
427  *
428  * Returns:
429  * The drm file descriptor or -1 on error
430  */
drm_open_driver_render(int chipset)431 int drm_open_driver_render(int chipset)
432 {
433 	static int open_count;
434 	int fd = __drm_open_driver_render(chipset);
435 
436 	/* no render nodes, fallback to drm_open_driver() */
437 	if (fd == -1)
438 		return drm_open_driver(chipset);
439 
440 	if (__sync_fetch_and_add(&open_count, 1))
441 		return fd;
442 
443 	at_exit_drm_render_fd = __drm_open_driver(chipset);
444 	if(chipset & DRIVER_INTEL){
445 		gem_quiescent_gpu(fd);
446 		igt_install_exit_handler(cancel_work_at_exit_render);
447 	}
448 
449 	return fd;
450 }
451 
igt_require_amdgpu(int fd)452 void igt_require_amdgpu(int fd)
453 {
454 	igt_require(is_amdgpu_device(fd));
455 }
456 
igt_require_intel(int fd)457 void igt_require_intel(int fd)
458 {
459 	igt_require(is_i915_device(fd) && has_known_intel_chipset(fd));
460 }
461 
igt_require_vc4(int fd)462 void igt_require_vc4(int fd)
463 {
464 	igt_require(is_vc4_device(fd));
465 }
466