i915_pm_rpm.c 53 KB
Newer Older
Paulo Zanoni's avatar
Paulo Zanoni committed
1
/*
2
 * Copyright © 2013, 2015 Intel Corporation
Paulo Zanoni's avatar
Paulo Zanoni committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Paulo Zanoni <paulo.r.zanoni@intel.com>
 *
 */

28 29
#include "config.h"

Paulo Zanoni's avatar
Paulo Zanoni committed
30 31 32 33
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
34
#include <ftw.h>
Paulo Zanoni's avatar
Paulo Zanoni committed
35 36 37 38 39

#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
40
#include <sys/mman.h>
Paulo Zanoni's avatar
Paulo Zanoni committed
41 42 43 44 45
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

46 47
#include <drm.h>

48 49 50 51
#include "igt.h"
#include "igt_kmod.h"
#include "igt_sysfs.h"
#include "igt_debugfs.h"
52
#include "igt_device.h"
Paulo Zanoni's avatar
Paulo Zanoni committed
53

54 55 56 57 58
#define MSR_PKG_CST_CONFIG_CONTROL	0xE2
/* HSW/BDW: */
#define  PKG_CST_LIMIT_MASK		0xF
#define  PKG_CST_LIMIT_C8		0x6

Paulo Zanoni's avatar
Paulo Zanoni committed
59 60 61 62 63 64 65 66
#define MSR_PC8_RES	0x630
#define MSR_PC9_RES	0x631
#define MSR_PC10_RES	0x632

#define MAX_CONNECTORS	32
#define MAX_ENCODERS	32
#define MAX_CRTCS	16

67 68 69 70 71
enum pc8_status {
	PC8_ENABLED,
	PC8_DISABLED
};

72 73 74 75 76 77
enum screen_type {
	SCREEN_TYPE_LPSP,
	SCREEN_TYPE_NON_LPSP,
	SCREEN_TYPE_ANY,
};

78 79 80 81 82 83
enum plane_type {
	PLANE_OVERLAY,
	PLANE_PRIMARY,
	PLANE_CURSOR,
};

84 85 86 87
/* Wait flags */
#define DONT_WAIT	0
#define WAIT_STATUS	1
#define WAIT_PC8_RES	2
88
#define WAIT_EXTRA	4
89
#define USE_DPMS	8
90

91
int drm_fd, msr_fd, pc8_status_fd;
92
int debugfs;
93
bool has_runtime_pm, has_pc8;
Paulo Zanoni's avatar
Paulo Zanoni committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
struct mode_set_data ms_data;

/* Stuff used when creating FBs and mode setting. */
struct mode_set_data {
	drmModeResPtr res;
	drmModeConnectorPtr connectors[MAX_CONNECTORS];
	drmModePropertyBlobPtr edids[MAX_CONNECTORS];

	uint32_t devid;
};

/* Stuff we query at different times so we can compare. */
struct compare_data {
	drmModeResPtr res;
	drmModeEncoderPtr encoders[MAX_ENCODERS];
	drmModeConnectorPtr connectors[MAX_CONNECTORS];
	drmModeCrtcPtr crtcs[MAX_CRTCS];
	drmModePropertyBlobPtr edids[MAX_CONNECTORS];
};

114 115 116 117 118
struct modeset_params {
	uint32_t crtc_id;
	uint32_t connector_id;
	struct igt_fb fb;
	drmModeModeInfoPtr mode;
119 120
};

121 122 123 124
struct modeset_params lpsp_mode_params;
struct modeset_params non_lpsp_mode_params;
struct modeset_params *default_mode_params;

125 126
static int8_t *pm_data = NULL;

127 128
static int modprobe(const char *driver)
{
129
	return igt_kmod_load(driver, NULL);
130 131
}

Paulo Zanoni's avatar
Paulo Zanoni committed
132 133 134 135 136 137 138
/* If the read fails, then the machine doesn't support PC8+ residencies. */
static bool supports_pc8_plus_residencies(void)
{
	int rc;
	uint64_t val;

	rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC8_RES);
139
	if (rc != sizeof(val))
Paulo Zanoni's avatar
Paulo Zanoni committed
140 141
		return false;
	rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC9_RES);
142
	if (rc != sizeof(val))
Paulo Zanoni's avatar
Paulo Zanoni committed
143 144
		return false;
	rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC10_RES);
145
	if (rc != sizeof(val))
Paulo Zanoni's avatar
Paulo Zanoni committed
146 147
		return false;

148 149 150 151 152 153 154 155
	rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PKG_CST_CONFIG_CONTROL);
	if (rc != sizeof(val))
		return false;
	if ((val & PKG_CST_LIMIT_MASK) < PKG_CST_LIMIT_C8) {
		igt_info("PKG C-states limited below PC8 by the BIOS\n");
		return false;
	}

Paulo Zanoni's avatar
Paulo Zanoni committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	return true;
}

static uint64_t get_residency(uint32_t type)
{
	int rc;
	uint64_t ret;

	rc = pread(msr_fd, &ret, sizeof(uint64_t), type);
	igt_assert(rc == sizeof(ret));

	return ret;
}

static bool pc8_plus_residency_changed(unsigned int timeout_sec)
{
	uint64_t res_pc8, res_pc9, res_pc10;

	res_pc8 = get_residency(MSR_PC8_RES);
	res_pc9 = get_residency(MSR_PC9_RES);
	res_pc10 = get_residency(MSR_PC10_RES);

Paulo Zanoni's avatar
Paulo Zanoni committed
178 179 180 181
	return igt_wait(res_pc8 != get_residency(MSR_PC8_RES) ||
			res_pc9 != get_residency(MSR_PC9_RES) ||
			res_pc10 != get_residency(MSR_PC10_RES),
			timeout_sec * 1000, 100);
Paulo Zanoni's avatar
Paulo Zanoni committed
182 183
}

184
static enum pc8_status get_pc8_status(void)
Paulo Zanoni's avatar
Paulo Zanoni committed
185
{
186 187 188 189 190 191 192 193 194 195 196 197
	ssize_t n_read;
	char buf[150]; /* The whole file has less than 100 chars. */

	lseek(pc8_status_fd, 0, SEEK_SET);
	n_read = read(pc8_status_fd, buf, ARRAY_SIZE(buf));
	igt_assert(n_read >= 0);
	buf[n_read] = '\0';

	if (strstr(buf, "\nEnabled: yes\n"))
		return PC8_ENABLED;
	else
		return PC8_DISABLED;
Paulo Zanoni's avatar
Paulo Zanoni committed
198 199
}

200
static bool wait_for_pc8_status(enum pc8_status status)
Paulo Zanoni's avatar
Paulo Zanoni committed
201
{
Paulo Zanoni's avatar
Paulo Zanoni committed
202
	return igt_wait(get_pc8_status() == status, 10000, 100);
Paulo Zanoni's avatar
Paulo Zanoni committed
203 204
}

205 206 207
static bool wait_for_suspended(void)
{
	if (has_pc8 && !has_runtime_pm)
208
		return wait_for_pc8_status(PC8_ENABLED);
209
	else
210
		return igt_wait_for_pm_status(IGT_RUNTIME_PM_STATUS_SUSPENDED);
211 212 213 214 215
}

static bool wait_for_active(void)
{
	if (has_pc8 && !has_runtime_pm)
216
		return wait_for_pc8_status(PC8_DISABLED);
217
	else
218
		return igt_wait_for_pm_status(IGT_RUNTIME_PM_STATUS_ACTIVE);
219 220
}

221 222
static void disable_all_screens_dpms(struct mode_set_data *data)
{
223 224
	if (!data->res)
		return;
225

226
	for (int i = 0; i < data->res->count_connectors; i++) {
227 228 229 230 231 232
		drmModeConnectorPtr c = data->connectors[i];

		kmstest_set_connector_dpms(drm_fd, c, DRM_MODE_DPMS_OFF);
	}
}

Paulo Zanoni's avatar
Paulo Zanoni committed
233 234
static void disable_all_screens(struct mode_set_data *data)
{
235 236
	if (data->res)
		kmstest_unset_all_crtcs(drm_fd, data->res);
Paulo Zanoni's avatar
Paulo Zanoni committed
237 238
}

239 240 241 242 243
#define disable_all_screens_and_wait(data) do { \
	disable_all_screens(data); \
	igt_assert(wait_for_suspended()); \
} while (0)

244 245 246 247 248 249 250 251 252 253 254 255 256
static void disable_or_dpms_all_screens(struct mode_set_data *data, bool dpms)
{
	if (dpms)
		disable_all_screens_dpms(&ms_data);
	else
		disable_all_screens(&ms_data);
}

#define disable_or_dpms_all_screens_and_wait(data, dpms) do { \
	disable_or_dpms_all_screens((data), (dpms)); \
	igt_assert(wait_for_suspended()); \
} while (0)

257 258 259
static bool init_modeset_params_for_type(struct mode_set_data *data,
					 struct modeset_params *params,
					 enum screen_type type)
Paulo Zanoni's avatar
Paulo Zanoni committed
260
{
261
	drmModeConnectorPtr connector = NULL;
262
	drmModeModeInfoPtr mode = NULL;
Paulo Zanoni's avatar
Paulo Zanoni committed
263

264 265 266 267
	if (!data->res)
		return false;

	for (int i = 0; i < data->res->count_connectors; i++) {
Paulo Zanoni's avatar
Paulo Zanoni committed
268 269
		drmModeConnectorPtr c = data->connectors[i];

270 271 272 273 274 275 276 277
		if (type == SCREEN_TYPE_LPSP &&
		    c->connector_type != DRM_MODE_CONNECTOR_eDP)
			continue;

		if (type == SCREEN_TYPE_NON_LPSP &&
		    c->connector_type == DRM_MODE_CONNECTOR_eDP)
			continue;

Paulo Zanoni's avatar
Paulo Zanoni committed
278
		if (c->connection == DRM_MODE_CONNECTED && c->count_modes) {
279
			connector = c;
280
			mode = &c->modes[0];
Paulo Zanoni's avatar
Paulo Zanoni committed
281 282 283 284
			break;
		}
	}

285
	if (!connector)
286 287
		return false;

288 289 290
	igt_create_pattern_fb(drm_fd, mode->hdisplay, mode->vdisplay,
			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
			      &params->fb);
291

292 293
	params->crtc_id = kmstest_find_crtc_for_connector(drm_fd, data->res,
							  connector, 0);
294
	params->connector_id = connector->connector_id;
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
	params->mode = mode;

	return true;
}

static void init_modeset_cached_params(struct mode_set_data *data)
{
	bool lpsp, non_lpsp;

	lpsp = init_modeset_params_for_type(data, &lpsp_mode_params,
					    SCREEN_TYPE_LPSP);
	non_lpsp = init_modeset_params_for_type(data, &non_lpsp_mode_params,
						SCREEN_TYPE_NON_LPSP);

	if (lpsp)
		default_mode_params = &lpsp_mode_params;
	else if (non_lpsp)
		default_mode_params = &non_lpsp_mode_params;
	else
		default_mode_params = NULL;
315 316
}

317
static bool set_mode_for_params(struct modeset_params *params)
318 319 320
{
	int rc;

321 322 323 324
	rc = drmModeSetCrtc(drm_fd, params->crtc_id, params->fb.fb_id, 0, 0,
			    &params->connector_id, 1, params->mode);
	return (rc == 0);
}
325

326 327 328 329
#define set_mode_for_params_and_wait(params) do { \
	igt_assert(set_mode_for_params(params)); \
	igt_assert(wait_for_active()); \
} while (0)
Paulo Zanoni's avatar
Paulo Zanoni committed
330

331 332 333 334
static bool enable_one_screen_with_type(struct mode_set_data *data,
					enum screen_type type)
{
	struct modeset_params *params = NULL;
Paulo Zanoni's avatar
Paulo Zanoni committed
335

336 337 338 339 340 341 342 343 344 345 346 347 348
	switch (type) {
	case SCREEN_TYPE_ANY:
		params = default_mode_params;
		break;
	case SCREEN_TYPE_LPSP:
		params = &lpsp_mode_params;
		break;
	case SCREEN_TYPE_NON_LPSP:
		params = &non_lpsp_mode_params;
		break;
	default:
		igt_assert(0);
	}
349

350 351 352 353
	if (!params)
		return false;

	return set_mode_for_params(params);
354 355 356 357
}

static void enable_one_screen(struct mode_set_data *data)
{
358 359
	/* SKIP if there are no connected screens. */
	igt_require(enable_one_screen_with_type(data, SCREEN_TYPE_ANY));
Paulo Zanoni's avatar
Paulo Zanoni committed
360 361
}

362 363 364 365 366
#define enable_one_screen_and_wait(data) do { \
	enable_one_screen(data); \
	igt_assert(wait_for_active()); \
} while (0)

Paulo Zanoni's avatar
Paulo Zanoni committed
367 368 369
static drmModePropertyBlobPtr get_connector_edid(drmModeConnectorPtr connector,
						 int index)
{
370 371 372 373
	bool found;
	uint64_t prop_value;
	drmModePropertyPtr prop;
	drmModePropertyBlobPtr blob = NULL;
Paulo Zanoni's avatar
Paulo Zanoni committed
374

375 376 377
	found = kmstest_get_property(drm_fd, connector->connector_id,
				     DRM_MODE_OBJECT_CONNECTOR, "EDID",
				     NULL, &prop_value, &prop);
Paulo Zanoni's avatar
Paulo Zanoni committed
378

379 380 381
	if (found) {
		igt_assert(prop->flags & DRM_MODE_PROP_BLOB);
		igt_assert(prop->count_blobs == 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
382

383
		blob = drmModeGetPropertyBlob(drm_fd, prop_value);
Paulo Zanoni's avatar
Paulo Zanoni committed
384 385 386 387

		drmModeFreeProperty(prop);
	}

388
	return blob;
Paulo Zanoni's avatar
Paulo Zanoni committed
389 390 391 392 393
}

static void init_mode_set_data(struct mode_set_data *data)
{
	data->res = drmModeGetResources(drm_fd);
394 395 396 397 398 399 400
	if (data->res) {
		igt_assert(data->res->count_connectors <= MAX_CONNECTORS);
		for (int i = 0; i < data->res->count_connectors; i++) {
			data->connectors[i] = drmModeGetConnectorCurrent(drm_fd,
									 data->res->connectors[i]);
			data->edids[i] = get_connector_edid(data->connectors[i], i);
		}
Paulo Zanoni's avatar
Paulo Zanoni committed
401

402
		kmstest_set_vt_graphics_mode();
Paulo Zanoni's avatar
Paulo Zanoni committed
403 404 405
	}

	data->devid = intel_get_drm_devid(drm_fd);
406
	init_modeset_cached_params(&ms_data);
Paulo Zanoni's avatar
Paulo Zanoni committed
407 408 409 410
}

static void fini_mode_set_data(struct mode_set_data *data)
{
411 412 413 414 415 416
	if (data->res) {
		for (int i = 0; i < data->res->count_connectors; i++) {
			drmModeFreeConnector(data->connectors[i]);
			drmModeFreePropertyBlob(data->edids[i]);
		}
		drmModeFreeResources(data->res);
Paulo Zanoni's avatar
Paulo Zanoni committed
417 418 419 420 421 422 423 424
	}
}

static void get_drm_info(struct compare_data *data)
{
	int i;

	data->res = drmModeGetResources(drm_fd);
425 426
	if (!data->res)
		return;
Paulo Zanoni's avatar
Paulo Zanoni committed
427 428 429 430 431 432

	igt_assert(data->res->count_connectors <= MAX_CONNECTORS);
	igt_assert(data->res->count_encoders <= MAX_ENCODERS);
	igt_assert(data->res->count_crtcs <= MAX_CRTCS);

	for (i = 0; i < data->res->count_connectors; i++) {
433 434
		/* Don't use GetConnectorCurrent, we want to force a reprobe
		 * here. */
Paulo Zanoni's avatar
Paulo Zanoni committed
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
		data->connectors[i] = drmModeGetConnector(drm_fd,
						data->res->connectors[i]);
		data->edids[i] = get_connector_edid(data->connectors[i], i);
	}
	for (i = 0; i < data->res->count_encoders; i++)
		data->encoders[i] = drmModeGetEncoder(drm_fd,
						data->res->encoders[i]);
	for (i = 0; i < data->res->count_crtcs; i++)
		data->crtcs[i] = drmModeGetCrtc(drm_fd, data->res->crtcs[i]);
}

static void free_drm_info(struct compare_data *data)
{
	int i;

450 451 452
	if (!data->res)
		return;

Paulo Zanoni's avatar
Paulo Zanoni committed
453 454 455 456 457 458 459 460 461 462 463 464
	for (i = 0; i < data->res->count_connectors; i++) {
		drmModeFreeConnector(data->connectors[i]);
		drmModeFreePropertyBlob(data->edids[i]);
	}
	for (i = 0; i < data->res->count_encoders; i++)
		drmModeFreeEncoder(data->encoders[i]);
	for (i = 0; i < data->res->count_crtcs; i++)
		drmModeFreeCrtc(data->crtcs[i]);

	drmModeFreeResources(data->res);
}

465
#define COMPARE(d1, d2, data) igt_assert_eq(d1->data, d2->data)
Paulo Zanoni's avatar
Paulo Zanoni committed
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
#define COMPARE_ARRAY(d1, d2, size, data) do { \
	for (i = 0; i < size; i++) \
		igt_assert(d1->data[i] == d2->data[i]); \
} while (0)

static void assert_drm_resources_equal(struct compare_data *d1,
				       struct compare_data *d2)
{
	COMPARE(d1, d2, res->count_connectors);
	COMPARE(d1, d2, res->count_encoders);
	COMPARE(d1, d2, res->count_crtcs);
	COMPARE(d1, d2, res->min_width);
	COMPARE(d1, d2, res->max_width);
	COMPARE(d1, d2, res->min_height);
	COMPARE(d1, d2, res->max_height);
}

static void assert_modes_equal(drmModeModeInfoPtr m1, drmModeModeInfoPtr m2)
{
	COMPARE(m1, m2, clock);
	COMPARE(m1, m2, hdisplay);
	COMPARE(m1, m2, hsync_start);
	COMPARE(m1, m2, hsync_end);
	COMPARE(m1, m2, htotal);
	COMPARE(m1, m2, hskew);
	COMPARE(m1, m2, vdisplay);
	COMPARE(m1, m2, vsync_start);
	COMPARE(m1, m2, vsync_end);
	COMPARE(m1, m2, vtotal);
	COMPARE(m1, m2, vscan);
	COMPARE(m1, m2, vrefresh);
	COMPARE(m1, m2, flags);
	COMPARE(m1, m2, type);
	igt_assert(strcmp(m1->name, m2->name) == 0);
}

static void assert_drm_connectors_equal(drmModeConnectorPtr c1,
					drmModeConnectorPtr c2)
{
	int i;

	COMPARE(c1, c2, connector_id);
	COMPARE(c1, c2, connector_type);
	COMPARE(c1, c2, connector_type_id);
	COMPARE(c1, c2, mmWidth);
	COMPARE(c1, c2, mmHeight);
	COMPARE(c1, c2, count_modes);
	COMPARE(c1, c2, count_props);
	COMPARE(c1, c2, count_encoders);
	COMPARE_ARRAY(c1, c2, c1->count_props, props);
	COMPARE_ARRAY(c1, c2, c1->count_encoders, encoders);

	for (i = 0; i < c1->count_modes; i++)
		assert_modes_equal(&c1->modes[0], &c2->modes[0]);
}

static void assert_drm_encoders_equal(drmModeEncoderPtr e1,
				      drmModeEncoderPtr e2)
{
	COMPARE(e1, e2, encoder_id);
	COMPARE(e1, e2, encoder_type);
	COMPARE(e1, e2, possible_crtcs);
	COMPARE(e1, e2, possible_clones);
}

static void assert_drm_crtcs_equal(drmModeCrtcPtr c1, drmModeCrtcPtr c2)
{
	COMPARE(c1, c2, crtc_id);
}

static void assert_drm_edids_equal(drmModePropertyBlobPtr e1,
				   drmModePropertyBlobPtr e2)
{
	if (!e1 && !e2)
		return;
	igt_assert(e1 && e2);

	COMPARE(e1, e2, length);

	igt_assert(memcmp(e1->data, e2->data, e1->length) == 0);
}

static void assert_drm_infos_equal(struct compare_data *d1,
				   struct compare_data *d2)
{
	int i;

553 554 555 556 557 558
	if (d1->res == d2->res)
		return;

	igt_assert(d1->res);
	igt_assert(d2->res);

Paulo Zanoni's avatar
Paulo Zanoni committed
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
	assert_drm_resources_equal(d1, d2);

	for (i = 0; i < d1->res->count_connectors; i++) {
		assert_drm_connectors_equal(d1->connectors[i],
					    d2->connectors[i]);
		assert_drm_edids_equal(d1->edids[i], d2->edids[i]);
	}

	for (i = 0; i < d1->res->count_encoders; i++)
		assert_drm_encoders_equal(d1->encoders[i], d2->encoders[i]);

	for (i = 0; i < d1->res->count_crtcs; i++)
		assert_drm_crtcs_equal(d1->crtcs[i], d2->crtcs[i]);
}

/* We could check the checksum too, but just the header is probably enough. */
static bool edid_is_valid(const unsigned char *edid)
{
	char edid_header[] = {
		0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
	};

	return (memcmp(edid, edid_header, sizeof(edid_header)) == 0);
}

static int count_drm_valid_edids(struct mode_set_data *data)
{
586 587 588 589
	int ret = 0;

	if (!data->res)
		return 0;
Paulo Zanoni's avatar
Paulo Zanoni committed
590

591
	for (int i = 0; i < data->res->count_connectors; i++)
Paulo Zanoni's avatar
Paulo Zanoni committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
		if (data->edids[i] && edid_is_valid(data->edids[i]->data))
			ret++;
	return ret;
}

static bool i2c_edid_is_valid(int fd)
{
	int rc;
	unsigned char edid[128] = {};
	struct i2c_msg msgs[] = {
		{ /* Start at 0. */
			.addr = 0x50,
			.flags = 0,
			.len = 1,
			.buf = edid,
		}, { /* Now read the EDID. */
			.addr = 0x50,
			.flags = I2C_M_RD,
			.len = 128,
			.buf = edid,
		}
	};
	struct i2c_rdwr_ioctl_data msgset = {
		.msgs = msgs,
		.nmsgs = 2,
	};

	rc = ioctl(fd, I2C_RDWR, &msgset);
	return (rc >= 0) ? edid_is_valid(edid) : false;
}

static int count_i2c_valid_edids(void)
{
	int fd, ret = 0;
	DIR *dir;

	struct dirent *dirent;
629
	char full_name[PATH_MAX];
Paulo Zanoni's avatar
Paulo Zanoni committed
630 631 632 633 634 635

	dir = opendir("/dev/");
	igt_assert(dir);

	while ((dirent = readdir(dir))) {
		if (strncmp(dirent->d_name, "i2c-", 4) == 0) {
636
			sprintf(full_name, "/dev/%s", dirent->d_name);
Paulo Zanoni's avatar
Paulo Zanoni committed
637
			fd = open(full_name, O_RDWR);
638
			igt_assert_neq(fd, -1);
Paulo Zanoni's avatar
Paulo Zanoni committed
639 640 641 642 643 644 645 646
			if (i2c_edid_is_valid(fd))
				ret++;
			close(fd);
		}
	}

	closedir(dir);

647
	return ret;
Paulo Zanoni's avatar
Paulo Zanoni committed
648 649
}

650 651
static int count_vga_outputs(struct mode_set_data *data)
{
652 653 654 655
	int count = 0;

	if (!data->res)
		return 0;
656

657
	for (int i = 0; i < data->res->count_connectors; i++)
658 659 660 661 662 663 664
		if (data->connectors[i]->connector_type ==
		    DRM_MODE_CONNECTOR_VGA)
			count++;

	return count;
}

665
static void test_i2c(struct mode_set_data *data)
Paulo Zanoni's avatar
Paulo Zanoni committed
666 667 668
{
	int i2c_edids = count_i2c_valid_edids();
	int drm_edids = count_drm_valid_edids(data);
669 670 671 672 673 674 675 676 677 678 679 680 681
	int vga_outputs = count_vga_outputs(data);
	int diff;

	igt_debug("i2c edids:%d drm edids:%d vga outputs:%d\n",
		  i2c_edids, drm_edids, vga_outputs);

	/* We fail to detect some VGA monitors using our i2c method. If you look
	 * at the dmesg of these cases, you'll see the Kernel complaining about
	 * the EDID reading mostly FFs and then disabling bit-banging. Since we
	 * don't want to reimplement everything the Kernel does, let's just
	 * accept the fact that some VGA outputs won't be properly detected. */
	diff = drm_edids - i2c_edids;
	igt_assert(diff <= vga_outputs && diff >= 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
682 683
}

684 685 686
static void setup_pc8(void)
{
	has_pc8 = false;
Paulo Zanoni's avatar
Paulo Zanoni committed
687 688

	/* Only Haswell supports the PC8 feature. */
689
	if (!IS_HASWELL(ms_data.devid) && !IS_BROADWELL(ms_data.devid))
690
		return;
Paulo Zanoni's avatar
Paulo Zanoni committed
691 692

	/* Make sure our Kernel supports MSR and the module is loaded. */
693
	igt_require(modprobe("msr") == 0);
694

Paulo Zanoni's avatar
Paulo Zanoni committed
695
	msr_fd = open("/dev/cpu/0/msr", O_RDONLY);
696 697
	igt_assert_f(msr_fd >= 0,
		     "Can't open /dev/cpu/0/msr.\n");
Paulo Zanoni's avatar
Paulo Zanoni committed
698 699

	/* Non-ULT machines don't support PC8+. */
700 701 702
	if (!supports_pc8_plus_residencies())
		return;

703
	pc8_status_fd = openat(debugfs, "i915_pc8_status", O_RDONLY);
704
	if (pc8_status_fd == -1)
705 706
		pc8_status_fd = openat(debugfs,
				       "i915_runtime_pm_status", O_RDONLY);
707
	igt_assert_f(pc8_status_fd >= 0,
708
		     "Can't open /sys/kernel/debug/dri/0/i915_runtime_pm_status");
709

710 711 712
	has_pc8 = true;
}

713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
static bool dmc_loaded(void)
{
	char buf[15];
	int len;

	len = igt_sysfs_read(debugfs, "i915_dmc_info", buf, sizeof(buf) - 1);
	if (len < 0)
	    return true; /* no CSR support, no DMC requirement */

	buf[len] = '\0';

	igt_info("DMC: %s\n", buf);
	return strstr(buf, "fw loaded: yes");
}

728 729 730 731 732 733 734 735 736 737 738 739
static void dump_file(int dir, const char *filename)
{
	char *contents;

	contents = igt_sysfs_get(dir, filename);
	if (!contents)
		return;

	igt_info("%s:\n%s\n", filename, contents);
	free(contents);
}

740
static bool setup_environment(void)
741
{
742 743 744
	if (has_runtime_pm)
		goto out;

745 746 747 748
	drm_fd = __drm_open_driver(DRIVER_INTEL);
	igt_require(drm_fd != -1);
	igt_device_set_master(drm_fd);

749 750
	debugfs = igt_debugfs_dir(drm_fd);
	igt_require(debugfs != -1);
751

752 753
	init_mode_set_data(&ms_data);

754
	pm_data = igt_pm_enable_sata_link_power_management();
755

756
	has_runtime_pm = igt_setup_runtime_pm();
757 758
	setup_pc8();

759 760
	igt_info("Runtime PM support: %d\n", has_runtime_pm);
	igt_info("PC8 residency support: %d\n", has_pc8);
761
	igt_require(has_runtime_pm);
762
	igt_require(dmc_loaded());
763 764 765

out:
	disable_all_screens(&ms_data);
766 767
	dump_file(debugfs, "i915_runtime_pm_status");

768
	return wait_for_suspended();
769
}
770

771
static void teardown_environment(void)
772
{
773 774 775 776 777 778
	close(msr_fd);
	if (has_pc8)
		close(pc8_status_fd);

	igt_restore_runtime_pm();

779 780
	igt_pm_restore_sata_link_power_management(pm_data);
	free(pm_data);
Paulo Zanoni's avatar
Paulo Zanoni committed
781

782
	fini_mode_set_data(&ms_data);
783

784
	close(debugfs);
785 786 787
	close(drm_fd);

	has_runtime_pm = false;
788 789
}

Daniel Vetter's avatar
Daniel Vetter committed
790 791
static void basic_subtest(void)
{
792
	disable_all_screens_and_wait(&ms_data);
793

794 795 796 797
	if (ms_data.res)
		enable_one_screen_and_wait(&ms_data);

	/* XXX Also we can test wake up via exec nop */
798 799 800 801 802 803
}

static void pc8_residency_subtest(void)
{
	igt_require(has_pc8);

Paulo Zanoni's avatar
Paulo Zanoni committed
804 805
	/* Make sure PC8+ residencies move! */
	disable_all_screens(&ms_data);
806
	igt_assert_f(pc8_plus_residency_changed(30),
807 808
		     "Machine is not reaching PC8+ states, please check its "
		     "configuration.\n");
Paulo Zanoni's avatar
Paulo Zanoni committed
809 810 811

	/* Make sure PC8+ residencies stop! */
	enable_one_screen(&ms_data);
812
	igt_assert_f(!pc8_plus_residency_changed(10),
813
		     "PC8+ residency didn't stop with screen enabled.\n");
Paulo Zanoni's avatar
Paulo Zanoni committed
814 815
}

816
static void modeset_subtest(enum screen_type type, int rounds, int wait_flags)
817
{
818
	int i;
819

820 821 822
	if (wait_flags & WAIT_PC8_RES)
		igt_require(has_pc8);

823 824 825
	if (wait_flags & WAIT_EXTRA)
		rounds /= 2;

826
	for (i = 0; i < rounds; i++) {
827 828 829 830 831
		if (wait_flags & USE_DPMS)
			disable_all_screens_dpms(&ms_data);
		else
			disable_all_screens(&ms_data);

832
		if (wait_flags & WAIT_STATUS)
833
			igt_assert(wait_for_suspended());
834
		if (wait_flags & WAIT_PC8_RES)
835
			igt_assert(pc8_plus_residency_changed(30));
836 837
		if (wait_flags & WAIT_EXTRA)
			sleep(5);
838 839 840 841

		/* If we skip this line it's because the type of screen we want
		 * is not connected. */
		igt_require(enable_one_screen_with_type(&ms_data, type));
842
		if (wait_flags & WAIT_STATUS)
843
			igt_assert(wait_for_active());
844 845
		if (wait_flags & WAIT_PC8_RES)
			igt_assert(!pc8_plus_residency_changed(5));
846 847
		if (wait_flags & WAIT_EXTRA)
			sleep(5);
848 849 850
	}
}

Paulo Zanoni's avatar
Paulo Zanoni committed
851 852 853 854 855 856
/* Test of the DRM resources reported by the IOCTLs are still the same. This
 * ensures we still see the monitors with the same eyes. We get the EDIDs and
 * compare them, which ensures we use DP AUX or GMBUS depending on what's
 * connected. */
static void drm_resources_equal_subtest(void)
{
857
	struct compare_data pre_suspend, during_suspend, post_suspend;
Paulo Zanoni's avatar
Paulo Zanoni committed
858

859
	enable_one_screen_and_wait(&ms_data);
860
	get_drm_info(&pre_suspend);
861
	igt_assert(wait_for_active());
Paulo Zanoni's avatar
Paulo Zanoni committed
862

863
	disable_all_screens_and_wait(&ms_data);
864
	get_drm_info(&during_suspend);
865
	igt_assert(wait_for_suspended());
Paulo Zanoni's avatar
Paulo Zanoni committed
866

867
	enable_one_screen_and_wait(&ms_data);
868
	get_drm_info(&post_suspend);
869
	igt_assert(wait_for_active());
Paulo Zanoni's avatar
Paulo Zanoni committed
870

871 872
	assert_drm_infos_equal(&pre_suspend, &during_suspend);
	assert_drm_infos_equal(&pre_suspend, &post_suspend);
Paulo Zanoni's avatar
Paulo Zanoni committed
873

874 875 876
	free_drm_info(&pre_suspend);
	free_drm_info(&during_suspend);
	free_drm_info(&post_suspend);
Paulo Zanoni's avatar
Paulo Zanoni committed
877 878
}

879
static void i2c_subtest_check_environment(void)
Paulo Zanoni's avatar
Paulo Zanoni committed
880
{
881 882 883 884 885
	int i2c_dev_files = 0;
	DIR *dev_dir;
	struct dirent *dirent;

	/* Make sure the /dev/i2c-* files exist. */
886
	igt_require(modprobe("i2c-dev") == 0);
887

888 889 890 891 892 893 894 895
	dev_dir = opendir("/dev");
	igt_assert(dev_dir);
	while ((dirent = readdir(dev_dir))) {
		if (strncmp(dirent->d_name, "i2c-", 4) == 0)
			i2c_dev_files++;
	}
	closedir(dev_dir);
	igt_require(i2c_dev_files);
896 897 898 899 900 901
}

/* Try to use raw I2C, which also needs interrupts. */
static void i2c_subtest(void)
{
	i2c_subtest_check_environment();
Paulo Zanoni's avatar
Paulo Zanoni committed
902

903
	enable_one_screen_and_wait(&ms_data);
Paulo Zanoni's avatar
Paulo Zanoni committed
904

905
	disable_all_screens_and_wait(&ms_data);
906
	test_i2c(&ms_data);
907
	igt_assert(wait_for_suspended());
Paulo Zanoni's avatar
Paulo Zanoni committed
908 909 910 911

	enable_one_screen(&ms_data);
}

912 913 914 915
static int read_entry(const char *filepath,
		      const struct stat *info,
		      const int typeflag,
		      struct FTW *pathinfo)
916
{
917 918
	char buf[4096];
	int fd;
919 920
	int rc;

921 922
	igt_assert_f(wait_for_suspended(), "Before opening: %s (%s)\n",
		     filepath + pathinfo->base, filepath);
923

924 925 926 927 928
	fd = open(filepath, O_RDONLY | O_NONBLOCK);
	if (fd < 0) {
		igt_debug("Failed to open '%s': %m\n", filepath);
		return 0;
	}
929

930 931 932
	do {
		rc = read(fd, buf, sizeof(buf));
	} while (rc == sizeof(buf));
933

934
	close(fd);
935

936 937
	igt_assert_f(wait_for_suspended(), "After closing: %s (%s)\n",
		     filepath + pathinfo->base, filepath);
938

939 940
	return 0;
}
941

942 943 944 945
static void walk_fs(char *path)
{
	disable_all_screens_and_wait(&ms_data);
	nftw(path, read_entry, 20, FTW_PHYS | FTW_MOUNT);
946 947 948 949 950 951 952
}

/* This test will probably pass, with a small chance of hanging the machine in
 * case of bugs. Many of the bugs exercised by this patch just result in dmesg
 * errors, so a "pass" here should be confirmed by a check on dmesg. */
static void debugfs_read_subtest(void)
{
953
	char path[256];
954

955 956 957
	igt_require_f(igt_debugfs_path(drm_fd, path, sizeof(path)),
		      "Can't find the debugfs directory\n");
	walk_fs(path);
958 959 960 961 962
}

/* Read the comment on debugfs_read_subtest(). */
static void sysfs_read_subtest(void)
{
963
	char path[80];
964

965
	igt_require_f(igt_sysfs_path(drm_fd, path, sizeof(path)),
966 967
		      "Can't find the sysfs directory\n");
	walk_fs(path);
968 969 970 971 972 973 974
}

/* Make sure we don't suspend when we have the i915_forcewake_user file open. */
static void debugfs_forcewake_user_subtest(void)
{
	int fd, rc;

975
	igt_require(intel_gen(ms_data.devid) >= 6);
976

977
	disable_all_screens_and_wait(&ms_data);
978

979
	fd = igt_open_forcewake_handle(drm_fd);
980
	igt_require(fd >= 0);
981

982 983 984 985 986 987 988
	if (has_runtime_pm) {
		igt_assert(wait_for_active());
		sleep(10);
		igt_assert(wait_for_active());
	} else {
		igt_assert(wait_for_suspended());
	}
989 990

	rc = close(fd);
991
	igt_assert_eq(rc, 0);
992

993
	igt_assert(wait_for_suspended());
994 995
}

996 997 998 999 1000 1001 1002 1003
static void gem_mmap_subtest(bool gtt_mmap)
{
	int i;
	uint32_t handle;
	int buf_size = 8192;
	uint8_t *gem_buf;

	/* Create, map and set data while the device is active. */
1004
	enable_one_screen_and_wait(&ms_data);
1005 1006 1007

	handle = gem_create(drm_fd, buf_size);

1008
	if (gtt_mmap) {
1009
		gem_buf = gem_mmap__gtt(drm_fd, handle, buf_size,
1010
					PROT_READ | PROT_WRITE);
1011 1012
	}
	else {
1013
		gem_buf = gem_mmap__cpu(drm_fd, handle, 0, buf_size, 0);
1014
	}
1015 1016 1017 1018 1019 1020 1021 1022 1023


	for (i = 0; i < buf_size; i++)
		gem_buf[i] = i & 0xFF;

	for (i = 0; i < buf_size; i++)
		igt_assert(gem_buf[i] == (i & 0xFF));

	/* Now suspend, read and modify. */
1024
	disable_all_screens_and_wait(&ms_data);
1025 1026 1027

	for (i = 0; i < buf_size; i++)
		igt_assert(gem_buf[i] == (i & 0xFF));
1028
	igt_assert(wait_for_suspended());
1029 1030 1031

	for (i = 0; i < buf_size; i++)
		gem_buf[i] = (~i & 0xFF);
1032
	igt_assert(wait_for_suspended());
1033 1034

	/* Now resume and see if it's still there. */
1035
	enable_one_screen_and_wait(&ms_data);
1036 1037 1038 1039 1040 1041 1042
	for (i = 0; i < buf_size; i++)
		igt_assert(gem_buf[i] == (~i & 0xFF));

	igt_assert(munmap(gem_buf, buf_size) == 0);

	/* Now the opposite: suspend, and try to create the mmap while
	 * suspended. */
1043
	disable_all_screens_and_wait(&ms_data);
1044

1045
	if (gtt_mmap) {
1046
		gem_buf = gem_mmap__gtt(drm_fd, handle, buf_size,
1047
					PROT_READ | PROT_WRITE);
1048 1049
	}
	else {
1050
		gem_buf = gem_mmap__cpu(drm_fd, handle, 0, buf_size, 0);
1051
	}
1052

1053
	igt_assert(wait_for_suspended());
1054 1055 1056 1057 1058 1059 1060

	for (i = 0; i < buf_size; i++)
		gem_buf[i] = i & 0xFF;

	for (i = 0; i < buf_size; i++)
		igt_assert(gem_buf[i] == (i & 0xFF));

1061
	igt_assert(wait_for_suspended());
1062 1063

	/* Resume and check if it's still there. */
1064
	enable_one_screen_and_wait(&ms_data);
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
	for (i = 0; i < buf_size; i++)
		igt_assert(gem_buf[i] == (i & 0xFF));

	igt_assert(munmap(gem_buf, buf_size) == 0);
	gem_close(drm_fd, handle);
}

static void gem_pread_subtest(void)
{
	int i;
	uint32_t handle;
	int buf_size = 8192;
	uint8_t *cpu_buf, *read_buf;

	cpu_buf = malloc(buf_size);
	read_buf = malloc(buf_size);
	igt_assert(cpu_buf);
	igt_assert(read_buf);
	memset(cpu_buf, 0, buf_size);
	memset(read_buf, 0, buf_size);

	/* Create and set data while the device is active. */
1087
	enable_one_screen_and_wait(&ms_data);
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101

	handle = gem_create(drm_fd, buf_size);

	for (i = 0; i < buf_size; i++)
		cpu_buf[i] = i & 0xFF;

	gem_write(drm_fd, handle, 0, cpu_buf, buf_size);

	gem_read(drm_fd, handle, 0, read_buf, buf_size);

	for (i = 0; i < buf_size; i++)
		igt_assert(cpu_buf[i] == read_buf[i]);

	/* Now suspend, read and modify. */
1102
	disable_all_screens_and_wait(&ms_data);
1103 1104 1105 1106 1107 1108

	memset(read_buf, 0, buf_size);
	gem_read(drm_fd, handle, 0, read_buf, buf_size);

	for (i = 0; i < buf_size; i++)
		igt_assert(cpu_buf[i] == read_buf[i]);
1109
	igt_assert(wait_for_suspended());
1110 1111 1112 1113

	for (i = 0; i < buf_size; i++)
		cpu_buf[i] = (~i & 0xFF);
	gem_write(drm_fd, handle, 0, cpu_buf, buf_size);
1114
	igt_assert(wait_for_suspended());
1115 1116

	/* Now resume and see if it's still there. */
1117
	enable_one_screen_and_wait(&ms_data);
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132

	memset(read_buf, 0, buf_size);
	gem_read(drm_fd, handle, 0, read_buf, buf_size);

	for (i = 0; i < buf_size; i++)
		igt_assert(cpu_buf[i] == read_buf[i]);

	gem_close(drm_fd, handle);

	free(cpu_buf);
	free(read_buf);
}

/* Paints a square of color $color, size $width x $height, at position $x x $y
 * of $dst_handle, which contains pitch $pitch. */
1133 1134
static void submit_blt_cmd(uint32_t dst_handle, uint16_t x, uint16_t y,
			   uint16_t width, uint16_t height, uint32_t pitch,
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
			   uint32_t color, uint32_t *presumed_dst_offset)
{
	int i, reloc_pos;
	uint32_t batch_handle;
	int batch_size = 8 * sizeof(uint32_t);
	uint32_t batch_buf[batch_size];
	struct drm_i915_gem_execbuffer2 execbuf = {};
	struct drm_i915_gem_exec_object2 objs[2] = {{}, {}};
	struct drm_i915_gem_relocation_entry relocs[1] = {{}};
	struct drm_i915_gem_wait gem_wait;

	i = 0;

1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
	if (intel_gen(ms_data.devid) >= 8)
		batch_buf[i++] = XY_COLOR_BLT_CMD_NOLEN |
				 XY_COLOR_BLT_WRITE_ALPHA |
				 XY_COLOR_BLT_WRITE_RGB | 0x5;
	else
		batch_buf[i++] = XY_COLOR_BLT_CMD_NOLEN |
				 XY_COLOR_BLT_WRITE_ALPHA |
				 XY_COLOR_BLT_WRITE_RGB | 0x4;
	batch_buf[i++] = (3 << 24) | (0xF0 << 16) | (pitch);
	batch_buf[i++] = (y << 16) | x;
	batch_buf[i++] = ((y + height) << 16) | (x + width);
1159
	reloc_pos = i;
1160 1161 1162
	batch_buf[i++] = *presumed_dst_offset;
	if (intel_gen(ms_data.devid) >= 8)
		batch_buf[i++] = 0;
1163 1164 1165
	batch_buf[i++] = color;

	batch_buf[i++] = MI_BATCH_BUFFER_END;
1166 1167
	if (intel_gen(ms_data.devid) < 8)
		batch_buf[i++] = MI_NOOP;
1168 1169 1170 1171 1172 1173 1174

	igt_assert(i * sizeof(uint32_t) == batch_size);

	batch_handle = gem_create(drm_fd, batch_size);
	gem_write(drm_fd, batch_handle, 0, batch_buf, batch_size);

	relocs[0].target_handle = dst_handle;
1175
	relocs[0].delta = 0;
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
	relocs[0].offset = reloc_pos * sizeof(uint32_t);
	relocs[0].presumed_offset = *presumed_dst_offset;
	relocs[0].read_domains = 0;
	relocs[0].write_domain = I915_GEM_DOMAIN_RENDER;

	objs[0].handle = dst_handle;
	objs[0].alignment = 64;

	objs[1].handle = batch_handle;
	objs[1].relocation_count = 1;
1186
	objs[1].relocs_ptr = (uintptr_t)relocs;
1187

1188
	execbuf.buffers_ptr = (uintptr_t)objs;
1189 1190 1191 1192 1193
	execbuf.buffer_count = 2;
	execbuf.batch_len = batch_size;
	execbuf.flags = I915_EXEC_BLT;
	i915_execbuffer2_set_context_id(execbuf, 0);

1194
	gem_execbuf(drm_fd, &execbuf);
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222

	*presumed_dst_offset = relocs[0].presumed_offset;

	gem_wait.flags = 0;
	gem_wait.timeout_ns = 10000000000LL; /* 10s */

	gem_wait.bo_handle = batch_handle;
	do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_WAIT, &gem_wait);

	gem_wait.bo_handle = dst_handle;
	do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_WAIT, &gem_wait);

	gem_close(drm_fd, batch_handle);
}

/* Make sure we can submit a batch buffer and verify its result. */
static void gem_execbuf_subtest(void)
{
	int x, y;
	uint32_t handle;
	int bpp = 4;
	int pitch = 128 * bpp;
	int dst_size = 128 * 128 * bpp; /* 128x128 square */
	uint32_t *cpu_buf;
	uint32_t presumed_offset = 0;
	int sq_x = 5, sq_y = 10, sq_w = 15, sq_h = 20;
	uint32_t color;

1223 1224
	igt_require_gem(drm_fd);

1225
	/* Create and set data while the device is active. */
1226
	enable_one_screen_and_wait(&ms_data);
1227 1228 1229 1230 1231 1232 1233 1234 1235

	handle = gem_create(drm_fd, dst_size);

	cpu_buf = malloc(dst_size);
	igt_assert(cpu_buf);
	memset(cpu_buf, 0, dst_size);
	gem_write(drm_fd, handle, 0, cpu_buf, dst_size);

	/* Now suspend and try it. */
1236
	disable_all_screens_and_wait(&ms_data);
1237 1238 1239 1240

	color = 0x12345678;
	submit_blt_cmd(handle, sq_x, sq_y, sq_w, sq_h, pitch, color,
		       &presumed_offset);
1241
	igt_assert(wait_for_suspended());
1242 1243

	gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
1244
	igt_assert(wait_for_suspended());
1245 1246 1247 1248 1249 1250
	for (y = 0; y < 128; y++) {
		for (x = 0; x < 128; x++) {
			uint32_t px = cpu_buf[y * 128 + x];

			if (y >= sq_y && y < (sq_y + sq_h) &&
			    x >= sq_x && x < (sq_x + sq_w))
1251
				igt_assert_eq_u32(px, color);
1252 1253 1254 1255 1256 1257
			else
				igt_assert(px == 0);
		}
	}

	/* Now resume and check for it again. */
1258
	enable_one_screen_and_wait(&ms_data);
1259 1260 1261 1262 1263 1264 1265 1266 1267

	memset(cpu_buf, 0, dst_size);
	gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
	for (y = 0; y < 128; y++) {
		for (x = 0; x < 128; x++) {
			uint32_t px = cpu_buf[y * 128 + x];

			if (y >= sq_y && y < (sq_y + sq_h) &&
			    x >= sq_x && x < (sq_x + sq_w))
1268
				igt_assert_eq_u32(px, color);
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
			else
				igt_assert(px == 0);
		}
	}

	/* Now we'll do the opposite: do the blt while active, then read while
	 * suspended. We use the same spot, but a different color. As a bonus,
	 * we're testing the presumed_offset from the previous command. */
	color = 0x87654321;
	submit_blt_cmd(handle, sq_x, sq_y, sq_w, sq_h, pitch, color,
		       &presumed_offset);

1281
	disable_all_screens_and_wait(&ms_data);
1282 1283 1284 1285 1286 1287 1288 1289 1290

	memset(cpu_buf, 0, dst_size);
	gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
	for (y = 0; y < 128; y++) {
		for (x = 0; x < 128; x++) {
			uint32_t px = cpu_buf[y * 128 + x];

			if (y >= sq_y && y < (sq_y + sq_h) &&
			    x >= sq_x && x < (sq_x + sq_w))
1291
				igt_assert_eq_u32(px, color);
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
			else
				igt_assert(px == 0);
		}
	}

	gem_close(drm_fd, handle);

	free(cpu_buf);
}

/* Assuming execbuf already works, let's see what happens when we force many
 * suspend/resume cycles with commands. */
1304
static void gem_execbuf_stress_subtest(int rounds, int wait_flags)
1305 1306 1307 1308 1309 1310 1311 1312
{
	int i;
	int batch_size = 4 * sizeof(uint32_t);
	uint32_t batch_buf[batch_size];
	uint32_t handle;
	struct drm_i915_gem_execbuffer2 execbuf = {};
	struct drm_i915_gem_exec_object2 objs[1] = {{}};

1313 1314
	igt_require_gem(drm_fd);

1315 1316 1317
	if (wait_flags & WAIT_PC8_RES)
		igt_require(has_pc8);

1318 1319 1320 1321 1322 1323 1324
	i = 0;
	batch_buf[i++] = MI_NOOP;
	batch_buf[i++] = MI_NOOP;
	batch_buf[i++] = MI_BATCH_BUFFER_END;
	batch_buf[i++] = MI_NOOP;
	igt_assert(i * sizeof(uint32_t) == batch_size);

1325
	disable_all_screens_and_wait(&ms_data);
1326 1327 1328 1329 1330 1331

	handle = gem_create(drm_fd, batch_size);
	gem_write(drm_fd, handle, 0, batch_buf, batch_size);

	objs[0].handle = handle;

1332
	execbuf.buffers_ptr = (uintptr_t)objs;
1333 1334 1335 1336 1337
	execbuf.buffer_count = 1;
	execbuf.batch_len = batch_size;
	execbuf.flags = I915_EXEC_RENDER;
	i915_execbuffer2_set_context_id(execbuf, 0);

1338
	for (i = 0; i < rounds; i++) {
1339
		gem_execbuf(drm_fd, &execbuf);
1340 1341 1342 1343

		if (wait_flags & WAIT_STATUS)
			igt_assert(wait_for_suspended());
		if (wait_flags & WAIT_PC8_RES)
1344
			igt_assert(pc8_plus_residency_changed(30));
1345 1346
		if (wait_flags & WAIT_EXTRA)
			sleep(5);
1347 1348 1349 1350 1351
	}

	gem_close(drm_fd, handle);
}

1352 1353 1354
/* When this test was written, it triggered WARNs and DRM_ERRORs on dmesg. */
static void gem_idle_subtest(void)
{
1355
	disable_all_screens_and_wait(&ms_data);
1356 1357 1358

	sleep(5);

1359
	gem_test_engine(drm_fd, -1);
1360 1361
}

1362 1363
static void gem_evict_pwrite_subtest(void)
{
1364 1365 1366 1367 1368
	struct {
		uint32_t handle;
		uint32_t *ptr;
	} *trash_bos;
	unsigned int num_trash_bos, n;
1369 1370
	uint32_t buf;

1371
	num_trash_bos = gem_mappable_aperture_size(drm_fd) / (1024*1024) + 1;
1372 1373
	trash_bos = malloc(num_trash_bos * sizeof(*trash_bos));
	igt_assert(trash_bos);
1374

1375 1376 1377 1378 1379 1380
	for (n = 0; n < num_trash_bos; n++) {
		trash_bos[n].handle = gem_create(drm_fd, 1024*1024);
		trash_bos[n].ptr = gem_mmap__gtt(drm_fd, trash_bos[n].handle,
						 1024*1024, PROT_WRITE);
		*trash_bos[n].ptr = 0;
	}
1381 1382 1383 1384 1385

	disable_or_dpms_all_screens_and_wait(&ms_data, true);
	igt_assert(wait_for_suspended());

	buf = 0;
1386 1387
	for (n = 0; n < num_trash_bos; n++)
		gem_write(drm_fd, trash_bos[n].handle, 0, &buf, sizeof(buf));
1388

1389 1390 1391 1392 1393
	for (n = 0; n < num_trash_bos; n++) {
		munmap(trash_bos[n].ptr, 1024*1024);
		gem_close(drm_fd, trash_bos[n].handle);
	}
	free(trash_bos);
1394 1395
}

1396 1397 1398 1399 1400 1401 1402
/* This also triggered WARNs on dmesg at some point. */
static void reg_read_ioctl_subtest(void)
{
	struct drm_i915_reg_read rr = {
		.offset = 0x2358, /* render ring timestamp */
	};

1403
	disable_all_screens_and_wait(&ms_data);
1404 1405 1406 1407 1408 1409

	do_ioctl(drm_fd, DRM_IOCTL_I915_REG_READ, &rr);

	igt_assert(wait_for_suspended());
}

1410 1411 1412
static bool device_in_pci_d3(void)
{
	uint16_t val;
1413
	int rc;
1414

1415
	rc = pci_device_cfg_read_u16(igt_device_get_pci_device(drm_fd), &val, 0xd4);
1416
	igt_assert_eq(rc, 0);
1417

1418
	igt_debug("%s: PCI D3 state=%d\n", __func__, val & 0x3);
1419 1420 1421 1422 1423 1424 1425
	return (val & 0x3) == 0x3;
}

static void pci_d3_state_subtest(void)
{
	igt_require(has_runtime_pm);

1426
	disable_all_screens_and_wait(&ms_data);
1427
	igt_assert(igt_wait(device_in_pci_d3(), 2000, 100));
1428

1429 1430 1431 1432
	if (ms_data.res) {
		enable_one_screen_and_wait(&ms_data);
		igt_assert(!device_in_pci_d3());
	}
1433 1434
}

1435
static void __attribute__((noreturn)) stay_subtest(void)
1436
{
1437
	disable_all_screens_and_wait(&ms_data);
1438 1439 1440 1441 1442

	while (1)
		sleep(600);
}

1443
static void system_suspend_subtest(int state, int debug)
1444
{
1445
	disable_all_screens_and_wait(&ms_data);
1446 1447

	igt_system_suspend_autoresume(state, debug);
1448 1449 1450
	igt_assert(wait_for_suspended());
}

1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
static void system_suspend_execbuf_subtest(void)
{
	int i;
	int batch_size = 4 * sizeof(uint32_t);
	uint32_t batch_buf[batch_size];
	uint32_t handle;
	struct drm_i915_gem_execbuffer2 execbuf = {};
	struct drm_i915_gem_exec_object2 objs[1] = {{}};

	i = 0;
	batch_buf[i++] = MI_NOOP;
	batch_buf[i++] = MI_NOOP;
	batch_buf[i++] = MI_BATCH_BUFFER_END;
	batch_buf[i++] = MI_NOOP;
	igt_assert(i * sizeof(uint32_t) == batch_size);

	handle = gem_create(drm_fd, batch_size);
	gem_write(drm_fd, handle, 0, batch_buf, batch_size);

	objs[0].handle = handle;

	execbuf.buffers_ptr = (uintptr_t)objs;
	execbuf.buffer_count = 1;
	execbuf.batch_len = batch_size;
	execbuf.flags = I915_EXEC_RENDER;
	i915_execbuffer2_set_context_id(execbuf, 0);

	disable_all_screens_and_wait(&ms_data);
1479
	igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE);
1480 1481 1482
	igt_assert(wait_for_suspended());

	for (i = 0; i < 20; i++) {
1483
		gem_execbuf(drm_fd, &execbuf);
1484 1485 1486 1487 1488 1489 1490 1491 1492
		igt_assert(wait_for_suspended());
	}

	gem_close(drm_fd, handle);
}

static void system_suspend_modeset_subtest(void)
{
	disable_all_screens_and_wait(&ms_data);
1493
	igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE);
1494 1495 1496 1497 1498 1499
	igt_assert(wait_for_suspended());

	enable_one_screen_and_wait(&ms_data);
	disable_all_screens_and_wait(&ms_data);
}

1500 1501 1502 1503
/* Enable a screen, activate DPMS, then do a modeset. At some point our driver
 * produced WARNs on this case. */
static void dpms_mode_unset_subtest(enum screen_type type)
{
1504
	disable_all_screens_and_wait(&ms_data);
1505 1506 1507 1508 1509 1510 1511

	igt_require(enable_one_screen_with_type(&ms_data, type));
	igt_assert(wait_for_active());

	disable_all_screens_dpms(&ms_data);
	igt_assert(wait_for_suspended());

1512
	disable_all_screens_and_wait(&ms_data);
1513 1514
}

1515 1516 1517 1518 1519
static void fill_igt_fb(struct igt_fb *fb, uint32_t color)
{
	int i;
	uint32_t *ptr;

1520
	ptr = gem_mmap__gtt(drm_fd, fb->gem_handle, fb->size, PROT_WRITE);
1521 1522 1523 1524 1525 1526 1527 1528 1529
	for (i = 0; i < fb->size/sizeof(uint32_t); i++)
		ptr[i] = color;
	igt_assert(munmap(ptr, fb->size) == 0);
}

/* At some point, this test triggered WARNs in the Kernel. */
static void cursor_subtest(bool dpms)
{
	int rc;
1530 1531
	struct igt_fb cursor_fb1, cursor_fb2, cursor_fb3;
	uint32_t crtc_id;
1532

1533
	disable_all_screens_and_wait(&ms_data);
1534

1535 1536
	igt_require(default_mode_params);
	crtc_id = default_mode_params->crtc_id;
1537

1538 1539 1540 1541
	igt_create_fb(drm_fd, 64, 64, DRM_FORMAT_ARGB8888,
		      LOCAL_DRM_FORMAT_MOD_NONE, &cursor_fb1);
	igt_create_fb(drm_fd, 64, 64, DRM_FORMAT_ARGB8888,
		      LOCAL_DRM_FORMAT_MOD_NONE, &cursor_fb2);
1542
	igt_create_fb(drm_fd, 64, 64, DRM_FORMAT_XRGB8888,
1543
		      LOCAL_I915_FORMAT_MOD_X_TILED, &cursor_fb3);
1544 1545 1546 1547 1548

	fill_igt_fb(&cursor_fb1, 0xFF00FFFF);
	fill_igt_fb(&cursor_fb2, 0xFF00FF00);
	fill_igt_fb(&cursor_fb3, 0xFFFF0000);