2 * Copyright © 2013 Intel Corporation
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:
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
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
24 * Paulo Zanoni <paulo.r.zanoni@intel.com>
36 #include <sys/ioctl.h>
38 #include <sys/types.h>
40 #include <linux/i2c.h>
41 #include <linux/i2c-dev.h>
45 #include "intel_batchbuffer.h"
46 #include "intel_gpu_tools.h"
50 #define MSR_PC8_RES 0x630
51 #define MSR_PC9_RES 0x631
52 #define MSR_PC10_RES 0x632
54 #define MAX_CONNECTORS 32
55 #define MAX_ENCODERS 32
70 struct mode_set_data ms_data;
72 /* Stuff used when creating FBs and mode setting. */
73 struct mode_set_data {
75 drmModeConnectorPtr connectors[MAX_CONNECTORS];
76 drmModePropertyBlobPtr edids[MAX_CONNECTORS];
81 /* Stuff we query at different times so we can compare. */
84 drmModeEncoderPtr encoders[MAX_ENCODERS];
85 drmModeConnectorPtr connectors[MAX_CONNECTORS];
86 drmModeCrtcPtr crtcs[MAX_CRTCS];
87 drmModePropertyBlobPtr edids[MAX_CONNECTORS];
90 struct compare_registers {
91 /* We know these are lost */
95 /* Stuff touched at init_clock_gating, so we can make sure we
96 * don't need to call it when reiniting. */
97 uint32_t gen6_ucgctl2;
98 uint32_t gen7_l3cntlreg1;
99 uint32_t transa_chicken1;
104 uint32_t ddi_buf_trans_a_1;
105 uint32_t ddi_buf_trans_b_5;
106 uint32_t ddi_buf_trans_c_10;
107 uint32_t ddi_buf_trans_d_15;
108 uint32_t ddi_buf_trans_e_20;
111 /* If the read fails, then the machine doesn't support PC8+ residencies. */
112 static bool supports_pc8_plus_residencies(void)
117 rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC8_RES);
118 if (rc != sizeof(val))
120 rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC9_RES);
121 if (rc != sizeof(val))
123 rc = pread(msr_fd, &val, sizeof(uint64_t), MSR_PC10_RES);
124 if (rc != sizeof(val))
130 static uint64_t get_residency(uint32_t type)
135 rc = pread(msr_fd, &ret, sizeof(uint64_t), type);
136 igt_assert(rc == sizeof(ret));
141 static bool pc8_plus_residency_changed(unsigned int timeout_sec)
144 uint64_t res_pc8, res_pc9, res_pc10;
145 int to_sleep = 100 * 1000;
147 res_pc8 = get_residency(MSR_PC8_RES);
148 res_pc9 = get_residency(MSR_PC9_RES);
149 res_pc10 = get_residency(MSR_PC10_RES);
151 for (i = 0; i < timeout_sec * 1000 * 1000; i += to_sleep) {
152 if (res_pc8 != get_residency(MSR_PC8_RES) ||
153 res_pc9 != get_residency(MSR_PC9_RES) ||
154 res_pc10 != get_residency(MSR_PC10_RES)) {
163 /* Checks not only if PC8+ is allowed, but also if we're reaching it.
164 * We call this when we expect this function to return quickly since PC8 is
165 * actually enabled, so the 30s timeout we use shouldn't matter. */
166 static bool pc8_plus_enabled(void)
168 return pc8_plus_residency_changed(30);
171 /* We call this when we expect PC8+ to be actually disabled, so we should not
172 * return until the 5s timeout expires. In other words: in the "happy case",
173 * every time we call this function the program will take 5s more to finish. */
174 static bool pc8_plus_disabled(void)
176 return !pc8_plus_residency_changed(5);
179 static void disable_all_screens(struct mode_set_data *data)
183 for (i = 0; i < data->res->count_crtcs; i++) {
184 rc = drmModeSetCrtc(drm_fd, data->res->crtcs[i], -1, 0, 0,
190 static uint32_t create_fb(struct mode_set_data *data, int width, int height)
192 struct kmstest_fb fb;
196 buffer_id = kmstest_create_fb(drm_fd, width, height, 32, 24, false,
198 cr = kmstest_get_cairo_ctx(drm_fd, &fb);
199 kmstest_paint_test_pattern(cr, width, height);
203 static bool enable_one_screen_with_type(struct mode_set_data *data,
204 enum screen_type type)
206 uint32_t crtc_id = 0, buffer_id = 0, connector_id = 0;
207 drmModeModeInfoPtr mode = NULL;
210 for (i = 0; i < data->res->count_connectors; i++) {
211 drmModeConnectorPtr c = data->connectors[i];
213 if (type == SCREEN_TYPE_LPSP &&
214 c->connector_type != DRM_MODE_CONNECTOR_eDP)
217 if (type == SCREEN_TYPE_NON_LPSP &&
218 c->connector_type == DRM_MODE_CONNECTOR_eDP)
221 if (c->connection == DRM_MODE_CONNECTED && c->count_modes) {
222 connector_id = c->connector_id;
228 if (connector_id == 0)
231 crtc_id = data->res->crtcs[0];
232 buffer_id = create_fb(data, mode->hdisplay, mode->vdisplay);
235 igt_assert(buffer_id);
236 igt_assert(connector_id);
239 rc = drmModeSetCrtc(drm_fd, crtc_id, buffer_id, 0, 0, &connector_id,
246 static void enable_one_screen(struct mode_set_data *data)
248 igt_assert(enable_one_screen_with_type(data, SCREEN_TYPE_ANY));
251 static drmModePropertyBlobPtr get_connector_edid(drmModeConnectorPtr connector,
255 drmModeObjectPropertiesPtr props;
256 drmModePropertyBlobPtr ret = NULL;
258 props = drmModeObjectGetProperties(drm_fd, connector->connector_id,
259 DRM_MODE_OBJECT_CONNECTOR);
261 for (i = 0; i < props->count_props; i++) {
262 drmModePropertyPtr prop = drmModeGetProperty(drm_fd,
265 if (strcmp(prop->name, "EDID") == 0) {
266 igt_assert(prop->flags & DRM_MODE_PROP_BLOB);
267 igt_assert(prop->count_blobs == 0);
268 ret = drmModeGetPropertyBlob(drm_fd,
269 props->prop_values[i]);
272 drmModeFreeProperty(prop);
275 drmModeFreeObjectProperties(props);
279 static void init_mode_set_data(struct mode_set_data *data)
283 data->res = drmModeGetResources(drm_fd);
284 igt_assert(data->res);
285 igt_assert(data->res->count_connectors <= MAX_CONNECTORS);
287 for (i = 0; i < data->res->count_connectors; i++) {
288 data->connectors[i] = drmModeGetConnector(drm_fd,
289 data->res->connectors[i]);
290 data->edids[i] = get_connector_edid(data->connectors[i], i);
293 data->devid = intel_get_drm_devid(drm_fd);
295 igt_set_vt_graphics_mode();
298 static void fini_mode_set_data(struct mode_set_data *data)
302 for (i = 0; i < data->res->count_connectors; i++) {
303 drmModeFreeConnector(data->connectors[i]);
304 drmModeFreePropertyBlob(data->edids[i]);
306 drmModeFreeResources(data->res);
309 static void get_drm_info(struct compare_data *data)
313 data->res = drmModeGetResources(drm_fd);
314 igt_assert(data->res);
316 igt_assert(data->res->count_connectors <= MAX_CONNECTORS);
317 igt_assert(data->res->count_encoders <= MAX_ENCODERS);
318 igt_assert(data->res->count_crtcs <= MAX_CRTCS);
320 for (i = 0; i < data->res->count_connectors; i++) {
321 data->connectors[i] = drmModeGetConnector(drm_fd,
322 data->res->connectors[i]);
323 data->edids[i] = get_connector_edid(data->connectors[i], i);
325 for (i = 0; i < data->res->count_encoders; i++)
326 data->encoders[i] = drmModeGetEncoder(drm_fd,
327 data->res->encoders[i]);
328 for (i = 0; i < data->res->count_crtcs; i++)
329 data->crtcs[i] = drmModeGetCrtc(drm_fd, data->res->crtcs[i]);
332 static void get_registers(struct compare_registers *data)
334 intel_register_access_init(intel_get_pci_device(), 0);
335 data->arb_mode = INREG(0x4030);
336 data->tilectl = INREG(0x101000);
337 data->gen6_ucgctl2 = INREG(0x9404);
338 data->gen7_l3cntlreg1 = INREG(0xB0C1);
339 data->transa_chicken1 = INREG(0xF0060);
340 data->deier = INREG(0x4400C);
341 data->gtier = INREG(0x4401C);
342 data->ddi_buf_trans_a_1 = INREG(0x64E00);
343 data->ddi_buf_trans_b_5 = INREG(0x64E70);
344 data->ddi_buf_trans_c_10 = INREG(0x64EE0);
345 data->ddi_buf_trans_d_15 = INREG(0x64F58);
346 data->ddi_buf_trans_e_20 = INREG(0x64FCC);
347 intel_register_access_fini();
350 static void free_drm_info(struct compare_data *data)
354 for (i = 0; i < data->res->count_connectors; i++) {
355 drmModeFreeConnector(data->connectors[i]);
356 drmModeFreePropertyBlob(data->edids[i]);
358 for (i = 0; i < data->res->count_encoders; i++)
359 drmModeFreeEncoder(data->encoders[i]);
360 for (i = 0; i < data->res->count_crtcs; i++)
361 drmModeFreeCrtc(data->crtcs[i]);
363 drmModeFreeResources(data->res);
366 #define COMPARE(d1, d2, data) igt_assert(d1->data == d2->data)
367 #define COMPARE_ARRAY(d1, d2, size, data) do { \
368 for (i = 0; i < size; i++) \
369 igt_assert(d1->data[i] == d2->data[i]); \
372 static void assert_drm_resources_equal(struct compare_data *d1,
373 struct compare_data *d2)
375 COMPARE(d1, d2, res->count_connectors);
376 COMPARE(d1, d2, res->count_encoders);
377 COMPARE(d1, d2, res->count_crtcs);
378 COMPARE(d1, d2, res->min_width);
379 COMPARE(d1, d2, res->max_width);
380 COMPARE(d1, d2, res->min_height);
381 COMPARE(d1, d2, res->max_height);
384 static void assert_modes_equal(drmModeModeInfoPtr m1, drmModeModeInfoPtr m2)
386 COMPARE(m1, m2, clock);
387 COMPARE(m1, m2, hdisplay);
388 COMPARE(m1, m2, hsync_start);
389 COMPARE(m1, m2, hsync_end);
390 COMPARE(m1, m2, htotal);
391 COMPARE(m1, m2, hskew);
392 COMPARE(m1, m2, vdisplay);
393 COMPARE(m1, m2, vsync_start);
394 COMPARE(m1, m2, vsync_end);
395 COMPARE(m1, m2, vtotal);
396 COMPARE(m1, m2, vscan);
397 COMPARE(m1, m2, vrefresh);
398 COMPARE(m1, m2, flags);
399 COMPARE(m1, m2, type);
400 igt_assert(strcmp(m1->name, m2->name) == 0);
403 static void assert_drm_connectors_equal(drmModeConnectorPtr c1,
404 drmModeConnectorPtr c2)
408 COMPARE(c1, c2, connector_id);
409 COMPARE(c1, c2, connector_type);
410 COMPARE(c1, c2, connector_type_id);
411 COMPARE(c1, c2, mmWidth);
412 COMPARE(c1, c2, mmHeight);
413 COMPARE(c1, c2, count_modes);
414 COMPARE(c1, c2, count_props);
415 COMPARE(c1, c2, count_encoders);
416 COMPARE_ARRAY(c1, c2, c1->count_props, props);
417 COMPARE_ARRAY(c1, c2, c1->count_encoders, encoders);
419 for (i = 0; i < c1->count_modes; i++)
420 assert_modes_equal(&c1->modes[0], &c2->modes[0]);
423 static void assert_drm_encoders_equal(drmModeEncoderPtr e1,
424 drmModeEncoderPtr e2)
426 COMPARE(e1, e2, encoder_id);
427 COMPARE(e1, e2, encoder_type);
428 COMPARE(e1, e2, possible_crtcs);
429 COMPARE(e1, e2, possible_clones);
432 static void assert_drm_crtcs_equal(drmModeCrtcPtr c1, drmModeCrtcPtr c2)
434 COMPARE(c1, c2, crtc_id);
437 static void assert_drm_edids_equal(drmModePropertyBlobPtr e1,
438 drmModePropertyBlobPtr e2)
442 igt_assert(e1 && e2);
445 COMPARE(e1, e2, length);
447 igt_assert(memcmp(e1->data, e2->data, e1->length) == 0);
450 static void compare_registers(struct compare_registers *d1,
451 struct compare_registers *d2)
453 COMPARE(d1, d2, gen6_ucgctl2);
454 COMPARE(d1, d2, gen7_l3cntlreg1);
455 COMPARE(d1, d2, transa_chicken1);
456 COMPARE(d1, d2, arb_mode);
457 COMPARE(d1, d2, tilectl);
458 COMPARE(d1, d2, arb_mode);
459 COMPARE(d1, d2, tilectl);
460 COMPARE(d1, d2, gtier);
461 COMPARE(d1, d2, ddi_buf_trans_a_1);
462 COMPARE(d1, d2, ddi_buf_trans_b_5);
463 COMPARE(d1, d2, ddi_buf_trans_c_10);
464 COMPARE(d1, d2, ddi_buf_trans_d_15);
465 COMPARE(d1, d2, ddi_buf_trans_e_20);
468 static void assert_drm_infos_equal(struct compare_data *d1,
469 struct compare_data *d2)
473 assert_drm_resources_equal(d1, d2);
475 for (i = 0; i < d1->res->count_connectors; i++) {
476 assert_drm_connectors_equal(d1->connectors[i],
478 assert_drm_edids_equal(d1->edids[i], d2->edids[i]);
481 for (i = 0; i < d1->res->count_encoders; i++)
482 assert_drm_encoders_equal(d1->encoders[i], d2->encoders[i]);
484 for (i = 0; i < d1->res->count_crtcs; i++)
485 assert_drm_crtcs_equal(d1->crtcs[i], d2->crtcs[i]);
488 /* We could check the checksum too, but just the header is probably enough. */
489 static bool edid_is_valid(const unsigned char *edid)
491 char edid_header[] = {
492 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,
495 return (memcmp(edid, edid_header, sizeof(edid_header)) == 0);
498 static int count_drm_valid_edids(struct mode_set_data *data)
502 for (i = 0; i < data->res->count_connectors; i++)
503 if (data->edids[i] && edid_is_valid(data->edids[i]->data))
508 static bool i2c_edid_is_valid(int fd)
511 unsigned char edid[128] = {};
512 struct i2c_msg msgs[] = {
518 }, { /* Now read the EDID. */
525 struct i2c_rdwr_ioctl_data msgset = {
530 rc = ioctl(fd, I2C_RDWR, &msgset);
531 return (rc >= 0) ? edid_is_valid(edid) : false;
534 static int count_i2c_valid_edids(void)
539 struct dirent *dirent;
542 dir = opendir("/dev/");
545 while ((dirent = readdir(dir))) {
546 if (strncmp(dirent->d_name, "i2c-", 4) == 0) {
547 snprintf(full_name, 32, "/dev/%s", dirent->d_name);
548 fd = open(full_name, O_RDWR);
549 igt_assert(fd != -1);
550 if (i2c_edid_is_valid(fd))
561 static void test_i2c(struct mode_set_data *data)
563 int i2c_edids = count_i2c_valid_edids();
564 int drm_edids = count_drm_valid_edids(data);
566 igt_assert(i2c_edids == drm_edids);
569 static void setup_environment(void)
571 drm_fd = drm_open_any();
572 igt_assert(drm_fd >= 0);
574 init_mode_set_data(&ms_data);
576 /* Only Haswell supports the PC8 feature. */
577 igt_require_f(IS_HASWELL(ms_data.devid),
578 "PC8+ feature only supported on Haswell.\n");
580 /* Make sure our Kernel supports MSR and the module is loaded. */
581 msr_fd = open("/dev/cpu/0/msr", O_RDONLY);
582 igt_assert_f(msr_fd >= 0,
583 "Can't open /dev/cpu/0/msr.\n");
585 /* Non-ULT machines don't support PC8+. */
586 igt_require_f(supports_pc8_plus_residencies(),
587 "Machine doesn't support PC8+ residencies.\n");
590 static void teardown_environment(void)
592 fini_mode_set_data(&ms_data);
597 static void basic_subtest(void)
599 /* Make sure PC8+ residencies move! */
600 disable_all_screens(&ms_data);
601 igt_assert_f(pc8_plus_enabled(),
602 "Machine is not reaching PC8+ states, please check its "
605 /* Make sure PC8+ residencies stop! */
606 enable_one_screen(&ms_data);
607 igt_assert_f(pc8_plus_disabled(),
608 "PC8+ residency didn't stop with screen enabled.\n");
611 static void modeset_subtest(enum screen_type type, int rounds,
612 enum residency_wait wait)
616 for (i = 0; i < rounds; i++) {
617 disable_all_screens(&ms_data);
619 igt_assert(pc8_plus_enabled());
621 /* If we skip this line it's because the type of screen we want
622 * is not connected. */
623 igt_require(enable_one_screen_with_type(&ms_data, type));
625 igt_assert(pc8_plus_disabled());
629 /* Test of the DRM resources reported by the IOCTLs are still the same. This
630 * ensures we still see the monitors with the same eyes. We get the EDIDs and
631 * compare them, which ensures we use DP AUX or GMBUS depending on what's
633 static void drm_resources_equal_subtest(void)
635 struct compare_data pre_pc8, during_pc8, post_pc8;
637 enable_one_screen(&ms_data);
638 igt_assert(pc8_plus_disabled());
639 get_drm_info(&pre_pc8);
640 igt_assert(pc8_plus_disabled());
642 disable_all_screens(&ms_data);
643 igt_assert(pc8_plus_enabled());
644 get_drm_info(&during_pc8);
645 igt_assert(pc8_plus_enabled());
647 enable_one_screen(&ms_data);
648 igt_assert(pc8_plus_disabled());
649 get_drm_info(&post_pc8);
650 igt_assert(pc8_plus_disabled());
652 assert_drm_infos_equal(&pre_pc8, &during_pc8);
653 assert_drm_infos_equal(&pre_pc8, &post_pc8);
655 free_drm_info(&pre_pc8);
656 free_drm_info(&during_pc8);
657 free_drm_info(&post_pc8);
660 static void i2c_subtest_check_environment(void)
662 int i2c_dev_files = 0;
664 struct dirent *dirent;
666 /* Make sure the /dev/i2c-* files exist. */
667 dev_dir = opendir("/dev");
669 while ((dirent = readdir(dev_dir))) {
670 if (strncmp(dirent->d_name, "i2c-", 4) == 0)
674 igt_require(i2c_dev_files);
677 /* Try to use raw I2C, which also needs interrupts. */
678 static void i2c_subtest(void)
680 i2c_subtest_check_environment();
682 enable_one_screen(&ms_data);
683 igt_assert(pc8_plus_disabled());
685 disable_all_screens(&ms_data);
686 igt_assert(pc8_plus_enabled());
688 igt_assert(pc8_plus_enabled());
690 enable_one_screen(&ms_data);
693 /* Just reading/writing registers from outside the Kernel is not really a safe
694 * thing to do on Haswell, so don't do this test on the default case. */
695 static void register_compare_subtest(void)
697 struct compare_registers pre_pc8, post_pc8;
699 enable_one_screen(&ms_data);
700 igt_assert(pc8_plus_disabled());
701 get_registers(&pre_pc8);
702 igt_assert(pc8_plus_disabled());
704 disable_all_screens(&ms_data);
705 igt_assert(pc8_plus_enabled());
706 enable_one_screen(&ms_data);
707 igt_assert(pc8_plus_disabled());
708 /* Wait for the registers to be restored. */
710 get_registers(&post_pc8);
711 igt_assert(pc8_plus_disabled());
713 compare_registers(&pre_pc8, &post_pc8);
716 static void read_full_file(const char *name)
721 igt_assert_f(pc8_plus_enabled(), "File: %s\n", name);
723 fd = open(name, O_RDONLY);
728 rc = read(fd, buf, ARRAY_SIZE(buf));
729 } while (rc == ARRAY_SIZE(buf));
734 igt_assert_f(pc8_plus_enabled(), "File: %s\n", name);
737 static void read_files_from_dir(const char *name, int level)
740 struct dirent *dirent;
747 full_name = malloc(PATH_MAX);
749 igt_assert(level < 128);
751 while ((dirent = readdir(dir))) {
752 struct stat stat_buf;
754 if (strcmp(dirent->d_name, ".") == 0)
756 if (strcmp(dirent->d_name, "..") == 0)
759 snprintf(full_name, PATH_MAX, "%s/%s", name, dirent->d_name);
761 rc = lstat(full_name, &stat_buf);
764 if (S_ISDIR(stat_buf.st_mode))
765 read_files_from_dir(full_name, level + 1);
767 if (S_ISREG(stat_buf.st_mode))
768 read_full_file(full_name);
775 /* This test will probably pass, with a small chance of hanging the machine in
776 * case of bugs. Many of the bugs exercised by this patch just result in dmesg
777 * errors, so a "pass" here should be confirmed by a check on dmesg. */
778 static void debugfs_read_subtest(void)
780 const char *path = "/sys/kernel/debug/dri/0";
784 igt_require_f(dir, "Can't open the debugfs directory\n");
787 disable_all_screens(&ms_data);
788 igt_assert(pc8_plus_enabled());
790 read_files_from_dir(path, 0);
793 /* Read the comment on debugfs_read_subtest(). */
794 static void sysfs_read_subtest(void)
796 const char *path = "/sys/devices/pci0000:00/0000:00:02.0";
800 igt_require_f(dir, "Can't open the sysfs directory\n");
803 disable_all_screens(&ms_data);
804 igt_assert(pc8_plus_enabled());
806 read_files_from_dir(path, 0);
809 /* Make sure we don't suspend when we have the i915_forcewake_user file open. */
810 static void debugfs_forcewake_user_subtest(void)
814 igt_require(!(IS_GEN2(ms_data.devid) || IS_GEN3(ms_data.devid) ||
815 IS_GEN4(ms_data.devid) || IS_GEN5(ms_data.devid)));
817 disable_all_screens(&ms_data);
818 igt_assert(pc8_plus_enabled());
820 fd = open("/sys/kernel/debug/dri/0/i915_forcewake_user", O_RDONLY);
823 igt_assert(pc8_plus_disabled());
828 igt_assert(pc8_plus_enabled());
831 static void gem_mmap_subtest(bool gtt_mmap)
838 /* Create, map and set data while the device is active. */
839 enable_one_screen(&ms_data);
840 igt_assert(pc8_plus_disabled());
842 handle = gem_create(drm_fd, buf_size);
845 gem_buf = gem_mmap__gtt(drm_fd, handle, buf_size,
846 PROT_READ | PROT_WRITE);
848 gem_buf = gem_mmap__cpu(drm_fd, handle, buf_size, 0);
851 for (i = 0; i < buf_size; i++)
852 gem_buf[i] = i & 0xFF;
854 for (i = 0; i < buf_size; i++)
855 igt_assert(gem_buf[i] == (i & 0xFF));
857 /* Now suspend, read and modify. */
858 disable_all_screens(&ms_data);
859 igt_assert(pc8_plus_enabled());
861 for (i = 0; i < buf_size; i++)
862 igt_assert(gem_buf[i] == (i & 0xFF));
863 igt_assert(pc8_plus_enabled());
865 for (i = 0; i < buf_size; i++)
866 gem_buf[i] = (~i & 0xFF);
867 igt_assert(pc8_plus_enabled());
869 /* Now resume and see if it's still there. */
870 enable_one_screen(&ms_data);
871 igt_assert(pc8_plus_disabled());
872 for (i = 0; i < buf_size; i++)
873 igt_assert(gem_buf[i] == (~i & 0xFF));
875 igt_assert(munmap(gem_buf, buf_size) == 0);
877 /* Now the opposite: suspend, and try to create the mmap while
879 disable_all_screens(&ms_data);
880 igt_assert(pc8_plus_enabled());
883 gem_buf = gem_mmap__gtt(drm_fd, handle, buf_size,
884 PROT_READ | PROT_WRITE);
886 gem_buf = gem_mmap__cpu(drm_fd, handle, buf_size, 0);
888 igt_assert(pc8_plus_enabled());
890 for (i = 0; i < buf_size; i++)
891 gem_buf[i] = i & 0xFF;
893 for (i = 0; i < buf_size; i++)
894 igt_assert(gem_buf[i] == (i & 0xFF));
896 igt_assert(pc8_plus_enabled());
898 /* Resume and check if it's still there. */
899 enable_one_screen(&ms_data);
900 igt_assert(pc8_plus_disabled());
901 for (i = 0; i < buf_size; i++)
902 igt_assert(gem_buf[i] == (i & 0xFF));
904 igt_assert(munmap(gem_buf, buf_size) == 0);
905 gem_close(drm_fd, handle);
908 static void gem_pread_subtest(void)
913 uint8_t *cpu_buf, *read_buf;
915 cpu_buf = malloc(buf_size);
916 read_buf = malloc(buf_size);
918 igt_assert(read_buf);
919 memset(cpu_buf, 0, buf_size);
920 memset(read_buf, 0, buf_size);
922 /* Create and set data while the device is active. */
923 enable_one_screen(&ms_data);
924 igt_assert(pc8_plus_disabled());
926 handle = gem_create(drm_fd, buf_size);
928 for (i = 0; i < buf_size; i++)
929 cpu_buf[i] = i & 0xFF;
931 gem_write(drm_fd, handle, 0, cpu_buf, buf_size);
933 gem_read(drm_fd, handle, 0, read_buf, buf_size);
935 for (i = 0; i < buf_size; i++)
936 igt_assert(cpu_buf[i] == read_buf[i]);
938 /* Now suspend, read and modify. */
939 disable_all_screens(&ms_data);
940 igt_assert(pc8_plus_enabled());
942 memset(read_buf, 0, buf_size);
943 gem_read(drm_fd, handle, 0, read_buf, buf_size);
945 for (i = 0; i < buf_size; i++)
946 igt_assert(cpu_buf[i] == read_buf[i]);
947 igt_assert(pc8_plus_enabled());
949 for (i = 0; i < buf_size; i++)
950 cpu_buf[i] = (~i & 0xFF);
951 gem_write(drm_fd, handle, 0, cpu_buf, buf_size);
952 igt_assert(pc8_plus_enabled());
954 /* Now resume and see if it's still there. */
955 enable_one_screen(&ms_data);
956 igt_assert(pc8_plus_disabled());
958 memset(read_buf, 0, buf_size);
959 gem_read(drm_fd, handle, 0, read_buf, buf_size);
961 for (i = 0; i < buf_size; i++)
962 igt_assert(cpu_buf[i] == read_buf[i]);
964 gem_close(drm_fd, handle);
970 /* Paints a square of color $color, size $width x $height, at position $x x $y
971 * of $dst_handle, which contains pitch $pitch. */
972 static void submit_blt_cmd(uint32_t dst_handle, uint32_t x, uint32_t y,
973 uint32_t width, uint32_t height, uint32_t pitch,
974 uint32_t color, uint32_t *presumed_dst_offset)
978 uint32_t batch_handle;
979 int batch_size = 8 * sizeof(uint32_t);
980 uint32_t batch_buf[batch_size];
981 uint32_t offset_in_dst = (pitch * y) + (x * bpp);
982 struct drm_i915_gem_execbuffer2 execbuf = {};
983 struct drm_i915_gem_exec_object2 objs[2] = {{}, {}};
984 struct drm_i915_gem_relocation_entry relocs[1] = {{}};
985 struct drm_i915_gem_wait gem_wait;
989 batch_buf[i++] = COLOR_BLT_CMD | COLOR_BLT_WRITE_ALPHA |
991 batch_buf[i++] = (3 << 24) | (0xF0 << 16) | pitch;
992 batch_buf[i++] = (height << 16) | width * bpp;
994 batch_buf[i++] = *presumed_dst_offset + offset_in_dst;
995 batch_buf[i++] = color;
997 batch_buf[i++] = MI_NOOP;
998 batch_buf[i++] = MI_BATCH_BUFFER_END;
999 batch_buf[i++] = MI_NOOP;
1001 igt_assert(i * sizeof(uint32_t) == batch_size);
1003 batch_handle = gem_create(drm_fd, batch_size);
1004 gem_write(drm_fd, batch_handle, 0, batch_buf, batch_size);
1006 relocs[0].target_handle = dst_handle;
1007 relocs[0].delta = offset_in_dst;
1008 relocs[0].offset = reloc_pos * sizeof(uint32_t);
1009 relocs[0].presumed_offset = *presumed_dst_offset;
1010 relocs[0].read_domains = 0;
1011 relocs[0].write_domain = I915_GEM_DOMAIN_RENDER;
1013 objs[0].handle = dst_handle;
1014 objs[0].alignment = 64;
1016 objs[1].handle = batch_handle;
1017 objs[1].relocation_count = 1;
1018 objs[1].relocs_ptr = (uintptr_t)relocs;
1020 execbuf.buffers_ptr = (uintptr_t)objs;
1021 execbuf.buffer_count = 2;
1022 execbuf.batch_len = batch_size;
1023 execbuf.flags = I915_EXEC_BLT;
1024 i915_execbuffer2_set_context_id(execbuf, 0);
1026 do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
1028 *presumed_dst_offset = relocs[0].presumed_offset;
1031 gem_wait.timeout_ns = 10000000000LL; /* 10s */
1033 gem_wait.bo_handle = batch_handle;
1034 do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_WAIT, &gem_wait);
1036 gem_wait.bo_handle = dst_handle;
1037 do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_WAIT, &gem_wait);
1039 gem_close(drm_fd, batch_handle);
1042 /* Make sure we can submit a batch buffer and verify its result. */
1043 static void gem_execbuf_subtest(void)
1048 int pitch = 128 * bpp;
1049 int dst_size = 128 * 128 * bpp; /* 128x128 square */
1051 uint32_t presumed_offset = 0;
1052 int sq_x = 5, sq_y = 10, sq_w = 15, sq_h = 20;
1055 /* Create and set data while the device is active. */
1056 enable_one_screen(&ms_data);
1057 igt_assert(pc8_plus_disabled());
1059 handle = gem_create(drm_fd, dst_size);
1061 cpu_buf = malloc(dst_size);
1062 igt_assert(cpu_buf);
1063 memset(cpu_buf, 0, dst_size);
1064 gem_write(drm_fd, handle, 0, cpu_buf, dst_size);
1066 /* Now suspend and try it. */
1067 disable_all_screens(&ms_data);
1068 igt_assert(pc8_plus_enabled());
1071 submit_blt_cmd(handle, sq_x, sq_y, sq_w, sq_h, pitch, color,
1073 igt_assert(pc8_plus_enabled());
1075 gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
1076 igt_assert(pc8_plus_enabled());
1077 for (y = 0; y < 128; y++) {
1078 for (x = 0; x < 128; x++) {
1079 uint32_t px = cpu_buf[y * 128 + x];
1081 if (y >= sq_y && y < (sq_y + sq_h) &&
1082 x >= sq_x && x < (sq_x + sq_w))
1083 igt_assert(px == color);
1085 igt_assert(px == 0);
1089 /* Now resume and check for it again. */
1090 enable_one_screen(&ms_data);
1091 igt_assert(pc8_plus_disabled());
1093 memset(cpu_buf, 0, dst_size);
1094 gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
1095 for (y = 0; y < 128; y++) {
1096 for (x = 0; x < 128; x++) {
1097 uint32_t px = cpu_buf[y * 128 + x];
1099 if (y >= sq_y && y < (sq_y + sq_h) &&
1100 x >= sq_x && x < (sq_x + sq_w))
1101 igt_assert(px == color);
1103 igt_assert(px == 0);
1107 /* Now we'll do the opposite: do the blt while active, then read while
1108 * suspended. We use the same spot, but a different color. As a bonus,
1109 * we're testing the presumed_offset from the previous command. */
1111 submit_blt_cmd(handle, sq_x, sq_y, sq_w, sq_h, pitch, color,
1114 disable_all_screens(&ms_data);
1115 igt_assert(pc8_plus_enabled());
1117 memset(cpu_buf, 0, dst_size);
1118 gem_read(drm_fd, handle, 0, cpu_buf, dst_size);
1119 for (y = 0; y < 128; y++) {
1120 for (x = 0; x < 128; x++) {
1121 uint32_t px = cpu_buf[y * 128 + x];
1123 if (y >= sq_y && y < (sq_y + sq_h) &&
1124 x >= sq_x && x < (sq_x + sq_w))
1125 igt_assert(px == color);
1127 igt_assert(px == 0);
1131 gem_close(drm_fd, handle);
1136 /* Assuming execbuf already works, let's see what happens when we force many
1137 * suspend/resume cycles with commands. */
1138 static void gem_execbuf_stress_subtest(void)
1142 int batch_size = 4 * sizeof(uint32_t);
1143 uint32_t batch_buf[batch_size];
1145 struct drm_i915_gem_execbuffer2 execbuf = {};
1146 struct drm_i915_gem_exec_object2 objs[1] = {{}};
1149 batch_buf[i++] = MI_NOOP;
1150 batch_buf[i++] = MI_NOOP;
1151 batch_buf[i++] = MI_BATCH_BUFFER_END;
1152 batch_buf[i++] = MI_NOOP;
1153 igt_assert(i * sizeof(uint32_t) == batch_size);
1155 disable_all_screens(&ms_data);
1156 igt_assert(pc8_plus_enabled());
1158 handle = gem_create(drm_fd, batch_size);
1159 gem_write(drm_fd, handle, 0, batch_buf, batch_size);
1161 objs[0].handle = handle;
1163 execbuf.buffers_ptr = (uintptr_t)objs;
1164 execbuf.buffer_count = 1;
1165 execbuf.batch_len = batch_size;
1166 execbuf.flags = I915_EXEC_RENDER;
1167 i915_execbuffer2_set_context_id(execbuf, 0);
1169 for (i = 0; i < max; i++) {
1170 do_ioctl(drm_fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
1171 igt_assert(pc8_plus_enabled());
1174 gem_close(drm_fd, handle);
1177 int main(int argc, char *argv[])
1179 bool do_register_compare = false;
1181 if (argc > 1 && strcmp(argv[1], "--do-register-compare") == 0)
1182 do_register_compare = true;
1184 igt_subtest_init(argc, argv);
1186 /* Skip instead of failing in case the machine is not prepared to reach
1187 * PC8+. We don't want bug reports from cases where the machine is just
1188 * not properly configured. */
1190 setup_environment();
1192 /* Essential things */
1195 igt_subtest("drm-resources-equal")
1196 drm_resources_equal_subtest();
1199 igt_subtest("modeset-lpsp")
1200 modeset_subtest(SCREEN_TYPE_LPSP, 1, WAIT);
1201 igt_subtest("modeset-non-lpsp")
1202 modeset_subtest(SCREEN_TYPE_NON_LPSP, 1, WAIT);
1205 igt_subtest("gem-mmap-cpu")
1206 gem_mmap_subtest(false);
1207 igt_subtest("gem-mmap-gtt")
1208 gem_mmap_subtest(true);
1209 igt_subtest("gem-pread")
1210 gem_pread_subtest();
1211 igt_subtest("gem-execbuf")
1212 gem_execbuf_subtest();
1217 igt_subtest("debugfs-read")
1218 debugfs_read_subtest();
1219 igt_subtest("debugfs-forcewake-user")
1220 debugfs_forcewake_user_subtest();
1221 igt_subtest("sysfs-read")
1222 sysfs_read_subtest();
1224 /* Modeset stress */
1225 igt_subtest("modeset-lpsp-stress")
1226 modeset_subtest(SCREEN_TYPE_LPSP, 50, WAIT);
1227 igt_subtest("modeset-non-lpsp-stress")
1228 modeset_subtest(SCREEN_TYPE_NON_LPSP, 50, WAIT);
1229 igt_subtest("modeset-lpsp-stress-no-wait")
1230 modeset_subtest(SCREEN_TYPE_LPSP, 50, DONT_WAIT);
1231 igt_subtest("modeset-non-lpsp-stress-no-wait")
1232 modeset_subtest(SCREEN_TYPE_NON_LPSP, 50, DONT_WAIT);
1235 igt_subtest("gem-execbuf-stress")
1236 gem_execbuf_stress_subtest();
1239 igt_subtest("register-compare") {
1240 igt_require(do_register_compare);
1241 register_compare_subtest();
1245 teardown_environment();