aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2019-08-22 11:30:45 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-08-22 11:30:45 -0700
commit206a8e3febc313c234301319fe1591dc3f92d812 (patch)
tree5d6743a29d41d23b45ed604e4b3b9e87e7cfc25c
parent4a12edecbca8c11abd6520a664e300f370d41397 (diff)
parent9149125daf306cd5b3b2688b53a779052fc88d93 (diff)
downloadplatform_external_igt-gpu-tools-206a8e3febc313c234301319fe1591dc3f92d812.tar.gz
platform_external_igt-gpu-tools-206a8e3febc313c234301319fe1591dc3f92d812.tar.bz2
platform_external_igt-gpu-tools-206a8e3febc313c234301319fe1591dc3f92d812.zip
Upgrade igt-gpu-tools to 357dbe1869d88a2f08bcee4eebceff4ee9014424 am: 22248ce8b1 am: 141ed12fec am: daa144e503
am: 9149125daf Change-Id: I704bd17efd512086961060e0757d3274dfd94798
-rw-r--r--METADATA6
-rw-r--r--README.md3
-rw-r--r--docs/chamelium.txt78
-rw-r--r--lib/Makefile.sources2
-rw-r--r--lib/i915/gem_ring.c5
-rw-r--r--lib/i915/gem_submission.c10
-rw-r--r--lib/igt_chamelium.c101
-rw-r--r--lib/igt_chamelium.h26
-rw-r--r--lib/igt_edid.c20
-rw-r--r--lib/igt_edid.h5
-rw-r--r--lib/igt_fb.c38
-rw-r--r--lib/igt_fb.h4
-rw-r--r--lib/igt_infoframe.c124
-rw-r--r--lib/igt_infoframe.h112
-rw-r--r--lib/igt_kms.c56
-rw-r--r--lib/igt_kms.h21
-rw-r--r--lib/intel_chipset.h3
-rw-r--r--lib/meson.build1
-rw-r--r--lib/sw_sync.c13
-rw-r--r--lib/tests/igt_audio.c2
-rw-r--r--lib/tests/igt_edid.c23
-rw-r--r--tests/Makefile.sources2
-rw-r--r--tests/debugfs_test.c21
-rw-r--r--tests/dmabuf.c32
-rw-r--r--tests/i915/gem_concurrent_all.c17
-rw-r--r--tests/i915/gem_ctx_engines.c40
-rw-r--r--tests/i915/gem_ctx_shared.c49
-rw-r--r--tests/i915/gem_eio.c21
-rw-r--r--tests/i915/gem_exec_fence.c2
-rw-r--r--tests/i915/gem_exec_schedule.c18
-rw-r--r--tests/i915/gem_mmap_gtt.c40
-rw-r--r--tests/i915/gem_mocs_settings.c68
-rw-r--r--tests/i915/gem_persistent_relocs.c9
-rw-r--r--tests/i915/gem_reloc_vs_gpu.c9
-rw-r--r--tests/i915/gem_shrink.c36
-rw-r--r--tests/i915/gem_userptr_blits.c49
-rw-r--r--tests/i915/i915_pm_rpm.c13
-rw-r--r--tests/i915/i915_pm_sseu.c2
-rwxr-xr-xtests/igt_command_line.sh2
-rw-r--r--tests/intel-ci/fast-feedback.testlist1
-rw-r--r--tests/kms_3d.c7
-rw-r--r--tests/kms_addfb_basic.c4
-rw-r--r--tests/kms_available_modes_crc.c3
-rw-r--r--tests/kms_ccs.c35
-rw-r--r--tests/kms_chamelium.c422
-rw-r--r--tests/kms_content_protection.c365
-rw-r--r--tests/kms_cursor_edge_walk.c2
-rw-r--r--tests/kms_hdmi_inject.c9
-rw-r--r--tests/kms_plane_multiple.c4
-rw-r--r--tests/kms_prime.c254
-rw-r--r--tests/kms_properties.c2
-rw-r--r--tests/meson.build2
-rw-r--r--tests/perf_pmu.c223
53 files changed, 1969 insertions, 447 deletions
diff --git a/METADATA b/METADATA
index aa97f6fb..518c48c1 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@ third_party {
type: GIT
value: "https://gitlab.freedesktop.org/drm/igt-gpu-tools"
}
- version: "1a5b48671e0863cb723e3d0239e54c828360dc99"
+ version: "357dbe1869d88a2f08bcee4eebceff4ee9014424"
license_type: NOTICE
last_upgrade_date {
year: 2019
- month: 7
- day: 22
+ month: 8
+ day: 21
}
}
diff --git a/README.md b/README.md
index 865ed6e0..b8c4c5a8 100644
--- a/README.md
+++ b/README.md
@@ -139,13 +139,16 @@ Requirements
This is a non-exhaustive list of package dependencies required for building
the default configuration (package names may vary):
+ bison
gtk-doc-tools
+ flex
libcairo2-dev
libdrm-dev
libkmod-dev
libpixman-1-dev
libpciaccess-dev
libprocps-dev
+ libudev-dev
libunwind-dev
liblzma-dev
libdw-dev
diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index aaa0646e..32c296f7 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -77,47 +77,43 @@ IGT's behavior can be configured through a configuration file.
By default, this file is expected to exist in ~/.igtrc
In order to run tests using the Chamelium, a valid configuration file must be
present. It must contain Chamelium-specific keys as shown with the following
-example:
-
-# The common configuration section follows.
-[Common]
-# The path to dump frames that fail comparison checks
-FrameDumpPath=/root/
-
-# The following section is used for configuring the Device Under Test.
-# It is not mandatory and allows overriding default values.
-[DUT]
-SuspendResumeDelay=15
-
-[Chamelium]
-# The URL used for connecting to the Chamelium's RPC server
-URL=http://192.168.1.2:9992
-
-# The rest of the sections are used for defining connector mappings.
-# This is required so any tests using the Chamelium know which connector
-# on the test machine should be connected to each Chamelium port.
-#
-# In the event that any of these mappings are specified incorrectly,
-# any hotplugging tests for the incorrect connector mapping will fail.
-
-# The name of the DRM connector
-# The DP-1 of [Chamelium:DP-1] and the HDMI-A-1 of [Chamelium:HDMI-A-1] indicate
-# "connector info type" of /sys/kernel/debug/dri/0/i915_display_info.
-[Chamelium:DP-1]
-# The ChameliumPortID indicates physical port (device) id of a Chamelium Board.
-# A Chamelium daemon program defines these port ids as
-# DP1 (located next to the HDMI port) = 1
-# DP2 (located next to the VGA connector) = 2
-# HDMI = 3 and VGA = 4
-# The port ids are defined at:
-# https://chromium.googlesource.com/chromiumos/platform/chameleon/+/master/chameleond/utils/ids.py
-ChameliumPortID=1
-
-[Chamelium:HDMI-A-2]
-ChameliumPortID=3
-
-[Chamelium:VGA-1]
-ChameliumPortID=4
+example (only Chamelium.URL is mandatory):
+
+ # The common configuration section follows.
+ [Common]
+ # The path to dump frames that fail comparison checks
+ FrameDumpPath=/root/
+
+ # The following section is used for configuring the Device Under Test.
+ # It is not mandatory and allows overriding default values.
+ [DUT]
+ SuspendResumeDelay=15
+
+ [Chamelium]
+ # The URL used for connecting to the Chamelium's RPC server
+ URL=http://192.168.1.2:9992
+
+ # The rest of the sections are used for defining connector mappings. This
+ # is optional, the mappings will be discovered automatically.
+
+ # The name of the DRM connector
+ # The DP-1 of [Chamelium:DP-1] and the HDMI-A-1 of [Chamelium:HDMI-A-1] indicate
+ # "connector info type" of /sys/kernel/debug/dri/0/i915_display_info.
+ [Chamelium:DP-1]
+ # The ChameliumPortID indicates physical port (device) id of a Chamelium Board.
+ # A Chamelium daemon program defines these port ids as
+ # DP1 (located next to the HDMI port) = 1
+ # DP2 (located next to the VGA connector) = 2
+ # HDMI = 3 and VGA = 4
+ # The port ids are defined at:
+ # https://chromium.googlesource.com/chromiumos/platform/chameleon/+/master/chameleond/utils/ids.py
+ ChameliumPortID=1
+
+ [Chamelium:HDMI-A-2]
+ ChameliumPortID=3
+
+ [Chamelium:VGA-1]
+ ChameliumPortID=4
Running the Chamelium With IGT
------------------------------
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e16de86e..cf094ab8 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -41,6 +41,8 @@ lib_source_list = \
igt_gvt.h \
igt_halffloat.c \
igt_halffloat.h \
+ igt_infoframe.c \
+ igt_infoframe.h \
igt_matrix.c \
igt_matrix.h \
igt_primes.c \
diff --git a/lib/i915/gem_ring.c b/lib/i915/gem_ring.c
index fdb9fc1b..bf7f439e 100644
--- a/lib/i915/gem_ring.c
+++ b/lib/i915/gem_ring.c
@@ -103,7 +103,7 @@ __gem_measure_ring_inflight(int fd, unsigned int engine, enum measure_ring_flags
} while (1);
igt_assert_eq(__execbuf(fd, &execbuf), -EINTR);
- igt_assert(count);
+ igt_assert(count > 1);
memset(&itv, 0, sizeof(itv));
setitimer(ITIMER_REAL, &itv, NULL);
@@ -118,7 +118,8 @@ __gem_measure_ring_inflight(int fd, unsigned int engine, enum measure_ring_flags
gem_quiescent_gpu(fd);
- return count;
+ /* Be conservative in case we must wrap later */
+ return count - 1;
}
/**
diff --git a/lib/i915/gem_submission.c b/lib/i915/gem_submission.c
index a8bb45c6..7602d7f6 100644
--- a/lib/i915/gem_submission.c
+++ b/lib/i915/gem_submission.c
@@ -74,7 +74,6 @@ unsigned gem_submission_method(int fd)
{
const int gen = intel_gen(intel_get_drm_devid(fd));
unsigned flags = 0;
- int result;
int dir;
@@ -87,14 +86,7 @@ unsigned gem_submission_method(int fd)
goto out;
}
- if (igt_sysfs_get_boolean(dir, "enable_guc_submission")) {
- flags |= GEM_SUBMISSION_GUC | GEM_SUBMISSION_EXECLISTS;
- goto out;
- }
-
- if (igt_sysfs_scanf(dir, "enable_execlists", "%d", &result) != 1)
- result = gen >= 8;
- if (result) {
+ if (gen >= 8) {
flags |= GEM_SUBMISSION_EXECLISTS;
goto out;
}
diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 301e9d21..1b03a103 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -351,6 +351,32 @@ static xmlrpc_value *chamelium_rpc(struct chamelium *chamelium,
return res;
}
+static bool __chamelium_is_reachable(struct chamelium *chamelium)
+{
+ xmlrpc_value *res;
+
+ /* GetSupportedInputs does not require a port and is harmless */
+ res = __chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
+
+ if (res != NULL)
+ xmlrpc_DECREF(res);
+
+ if (chamelium->env.fault_occurred)
+ igt_debug("Chamelium RPC call failed: %s\n",
+ chamelium->env.fault_string);
+
+ return !chamelium->env.fault_occurred;
+}
+
+void chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
+{
+ bool chamelium_online = igt_wait(__chamelium_is_reachable(chamelium),
+ timeout * 1000, 100);
+
+ igt_assert_f(chamelium_online,
+ "Couldn't connect to Chamelium for %ds", timeout);
+}
+
/**
* chamelium_plug:
* @chamelium: The Chamelium instance to use
@@ -562,10 +588,9 @@ static void chamelium_destroy_edid(struct chamelium *chamelium, int edid_id)
* Returns: An opaque pointer to the Chamelium EDID
*/
struct chamelium_edid *chamelium_new_edid(struct chamelium *chamelium,
- const unsigned char *raw_edid)
+ const struct edid *edid)
{
struct chamelium_edid *chamelium_edid;
- const struct edid *edid = (struct edid *) raw_edid;
size_t edid_size = edid_get_size(edid);
chamelium_edid = calloc(1, sizeof(struct chamelium_edid));
@@ -1124,6 +1149,78 @@ int chamelium_get_captured_frame_count(struct chamelium *chamelium)
return ret;
}
+bool chamelium_supports_get_last_infoframe(struct chamelium *chamelium)
+{
+ return chamelium_supports_method(chamelium, "GetLastInfoFrame");
+}
+
+static const char *
+chamelium_infoframe_type_str(enum chamelium_infoframe_type type)
+{
+ switch (type) {
+ case CHAMELIUM_INFOFRAME_AVI:
+ return "avi";
+ case CHAMELIUM_INFOFRAME_AUDIO:
+ return "audio";
+ case CHAMELIUM_INFOFRAME_MPEG:
+ return "mpeg";
+ case CHAMELIUM_INFOFRAME_VENDOR:
+ return "vendor";
+ }
+ assert(0); /* unreachable */
+}
+
+struct chamelium_infoframe *
+chamelium_get_last_infoframe(struct chamelium *chamelium,
+ struct chamelium_port *port,
+ enum chamelium_infoframe_type type)
+{
+ xmlrpc_value *res, *res_version, *res_payload;
+ struct chamelium_infoframe *infoframe;
+ const unsigned char *payload;
+
+ res = chamelium_rpc(chamelium, NULL, "GetLastInfoFrame", "(is)",
+ port->id, chamelium_infoframe_type_str(type));
+ xmlrpc_struct_find_value(&chamelium->env, res, "version", &res_version);
+ xmlrpc_struct_find_value(&chamelium->env, res, "payload", &res_payload);
+ infoframe = calloc(1, sizeof(*infoframe));
+ xmlrpc_read_int(&chamelium->env, res_version, &infoframe->version);
+ xmlrpc_read_base64(&chamelium->env, res_payload,
+ &infoframe->payload_size, &payload);
+ /* xmlrpc-c's docs say payload is actually not constant */
+ infoframe->payload = (uint8_t *) payload;
+ xmlrpc_DECREF(res_version);
+ xmlrpc_DECREF(res_payload);
+ xmlrpc_DECREF(res);
+
+ if (infoframe->payload_size == 0) {
+ chamelium_infoframe_destroy(infoframe);
+ return NULL;
+ }
+ return infoframe;
+}
+
+void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe)
+{
+ free(infoframe->payload);
+ free(infoframe);
+}
+
+bool chamelium_supports_trigger_link_failure(struct chamelium *chamelium)
+{
+ return chamelium_supports_method(chamelium, "TriggerLinkFailure");
+}
+
+/**
+ * chamelium_trigger_link_failure: trigger a link failure on the provided port.
+ */
+void chamelium_trigger_link_failure(struct chamelium *chamelium,
+ struct chamelium_port *port)
+{
+ xmlrpc_DECREF(chamelium_rpc(chamelium, port, "TriggerLinkFailure",
+ "(i)", port->id));
+}
+
bool chamelium_has_audio_support(struct chamelium *chamelium,
struct chamelium_port *port)
{
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index b6b7eb44..08705a9d 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -34,6 +34,7 @@
#include "igt_debugfs.h"
struct igt_fb;
+struct edid;
struct chamelium;
struct chamelium_port;
@@ -65,6 +66,19 @@ struct chamelium_audio_file {
int channels;
};
+enum chamelium_infoframe_type {
+ CHAMELIUM_INFOFRAME_AVI,
+ CHAMELIUM_INFOFRAME_AUDIO,
+ CHAMELIUM_INFOFRAME_MPEG,
+ CHAMELIUM_INFOFRAME_VENDOR,
+};
+
+struct chamelium_infoframe {
+ int version;
+ size_t payload_size;
+ uint8_t *payload;
+};
+
struct chamelium_edid;
/**
@@ -98,6 +112,7 @@ drmModeConnector *chamelium_port_get_connector(struct chamelium *chamelium,
bool reprobe);
const char *chamelium_port_get_name(struct chamelium_port *port);
+void chamelium_wait_reachable(struct chamelium *chamelium, int timeout);
void chamelium_plug(struct chamelium *chamelium, struct chamelium_port *port);
void chamelium_unplug(struct chamelium *chamelium, struct chamelium_port *port);
bool chamelium_is_plugged(struct chamelium *chamelium,
@@ -114,7 +129,7 @@ void chamelium_schedule_hpd_toggle(struct chamelium *chamelium,
struct chamelium_port *port, int delay_ms,
bool rising_edge);
struct chamelium_edid *chamelium_new_edid(struct chamelium *chamelium,
- const unsigned char *edid);
+ const struct edid *edid);
const struct edid *chamelium_edid_get_raw(struct chamelium_edid *edid,
struct chamelium_port *port);
void chamelium_port_set_edid(struct chamelium *chamelium,
@@ -141,6 +156,14 @@ void chamelium_start_capture(struct chamelium *chamelium,
void chamelium_stop_capture(struct chamelium *chamelium, int frame_count);
void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
int x, int y, int w, int h, int frame_count);
+bool chamelium_supports_get_last_infoframe(struct chamelium *chamelium);
+struct chamelium_infoframe *
+chamelium_get_last_infoframe(struct chamelium *chamelium,
+ struct chamelium_port *port,
+ enum chamelium_infoframe_type type);
+bool chamelium_supports_trigger_link_failure(struct chamelium *chamelium);
+void chamelium_trigger_link_failure(struct chamelium *chamelium,
+ struct chamelium_port *port);
bool chamelium_has_audio_support(struct chamelium *chamelium,
struct chamelium_port *port);
void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
@@ -185,5 +208,6 @@ void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
int height);
void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file);
+void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe);
#endif /* IGT_CHAMELIUM_H */
diff --git a/lib/igt_edid.c b/lib/igt_edid.c
index 1ad88970..1c85486d 100644
--- a/lib/igt_edid.c
+++ b/lib/igt_edid.c
@@ -296,12 +296,24 @@ static uint8_t compute_checksum(const uint8_t *buf, size_t size)
}
/**
- * edid_update_checksum: compute and update the EDID checksum
+ * edid_update_checksum: compute and update the checksums of the main EDID
+ * block and all extension blocks
*/
void edid_update_checksum(struct edid *edid)
{
+ size_t i;
+ struct edid_ext *ext;
+
edid->checksum = compute_checksum((uint8_t *) edid,
sizeof(struct edid));
+
+ for (i = 0; i < edid->extensions_len; i++) {
+ ext = &edid->extensions[i];
+ if (ext->tag == EDID_EXT_CEA)
+ ext->data.cea.checksum =
+ compute_checksum((uint8_t *) ext,
+ sizeof(struct edid_ext));
+ }
}
/**
@@ -465,9 +477,3 @@ void edid_ext_set_cea(struct edid_ext *ext, size_t data_blocks_size,
cea->dtd_start = 4 + data_blocks_size;
cea->misc = flags | num_native_dtds;
}
-
-void edid_ext_update_cea_checksum(struct edid_ext *ext)
-{
- ext->data.cea.checksum = compute_checksum((uint8_t *) ext,
- sizeof(struct edid_ext));
-}
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 606541ac..59b47a97 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -32,6 +32,8 @@
#include <xf86drmMode.h>
+#define EDID_BLOCK_SIZE 128
+
/**
* est_timings: set of established timings
*/
@@ -236,7 +238,7 @@ struct hdmi_vsdb {
uint8_t flags1; /* enum hdmi_vsdb_flags1 */
uint8_t max_tdms_clock; /* multiply by 5MHz */
uint8_t flags2; /* enum hdmi_vsdb_flags2 */
- char data[]; /* latency, misc, VIC, 3D */
+ uint8_t data[]; /* latency, misc, VIC, 3D */
} __attribute__((packed));
#define HDMI_VSDB_MIN_SIZE 2 /* just the source physical address */
@@ -366,7 +368,6 @@ void detailed_timing_set_string(struct detailed_timing *dt,
void cea_sad_init_pcm(struct cea_sad *sad, int channels,
uint8_t sampling_rates, uint8_t sample_sizes);
-void edid_ext_update_cea_checksum(struct edid_ext *ext);
const struct cea_vsdb *cea_vsdb_get_hdmi_default(size_t *size);
size_t edid_cea_data_block_set_sad(struct edid_cea_data_block *block,
const struct cea_sad *sads, size_t sads_len);
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index 5dc74a00..bad3eeca 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -485,12 +485,10 @@ static int fb_num_planes(const struct igt_fb *fb)
return format->num_planes;
}
-static void fb_init(struct igt_fb *fb,
- int fd, int width, int height,
- uint32_t drm_format,
- uint64_t modifier,
- enum igt_color_encoding color_encoding,
- enum igt_color_range color_range)
+void igt_init_fb(struct igt_fb *fb, int fd, int width, int height,
+ uint32_t drm_format, uint64_t modifier,
+ enum igt_color_encoding color_encoding,
+ enum igt_color_range color_range)
{
const struct format_desc_struct *f = lookup_drm_format(drm_format);
@@ -627,8 +625,8 @@ void igt_calc_fb_size(int fd, int width, int height, uint32_t drm_format, uint64
{
struct igt_fb fb;
- fb_init(&fb, fd, width, height, drm_format, modifier,
- IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
+ igt_init_fb(&fb, fd, width, height, drm_format, modifier,
+ IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
fb.size = calc_fb_size(&fb);
@@ -855,8 +853,8 @@ void igt_create_bo_for_fb(int fd, int width, int height,
uint32_t format, uint64_t modifier,
struct igt_fb *fb /* out */)
{
- fb_init(fb, fd, width, height, format, modifier,
- IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
+ igt_init_fb(fb, fd, width, height, format, modifier,
+ IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
create_bo_for_fb(fb);
}
@@ -885,8 +883,8 @@ int igt_create_bo_with_dimensions(int fd, int width, int height,
{
struct igt_fb fb;
- fb_init(&fb, fd, width, height, format, modifier,
- IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
+ igt_init_fb(&fb, fd, width, height, format, modifier,
+ IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
for (int i = 0; i < fb.num_planes; i++)
fb.strides[i] = stride;
@@ -1441,8 +1439,8 @@ igt_create_fb_with_bo_size(int fd, int width, int height,
{
uint32_t flags = 0;
- fb_init(fb, fd, width, height, format, modifier,
- color_encoding, color_range);
+ igt_init_fb(fb, fd, width, height, format, modifier,
+ color_encoding, color_range);
for (int i = 0; i < fb->num_planes; i++)
fb->strides[i] = bo_stride;
@@ -1974,9 +1972,9 @@ static void setup_linear_mapping(struct fb_blit_upload *blit)
* destination, tiling it at the same time.
*/
- fb_init(&linear->fb, fb->fd, fb->width, fb->height,
- fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
- fb->color_encoding, fb->color_range);
+ igt_init_fb(&linear->fb, fb->fd, fb->width, fb->height,
+ fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
+ fb->color_encoding, fb->color_range);
create_bo_for_fb(&linear->fb);
@@ -2130,9 +2128,9 @@ static void *igt_fb_create_cairo_shadow_buffer(int fd,
igt_assert(shadow);
- fb_init(shadow, fd, width, height,
- drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
- IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
+ igt_init_fb(shadow, fd, width, height,
+ drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
+ IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
shadow->strides[0] = ALIGN(width * (shadow->plane_bpp[0] / 8), 16);
shadow->size = ALIGN((uint64_t)shadow->strides[0] * height,
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index e19cc5d4..69132b41 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -117,6 +117,10 @@ void igt_get_fb_tile_size(int fd, uint64_t modifier, int fb_bpp,
unsigned *width_ret, unsigned *height_ret);
void igt_calc_fb_size(int fd, int width, int height, uint32_t format, uint64_t modifier,
uint64_t *size_ret, unsigned *stride_ret);
+void igt_init_fb(struct igt_fb *fb, int fd, int width, int height,
+ uint32_t drm_format, uint64_t modifier,
+ enum igt_color_encoding color_encoding,
+ enum igt_color_range color_range);
unsigned int
igt_create_fb_with_bo_size(int fd, int width, int height,
uint32_t format, uint64_t modifier,
diff --git a/lib/igt_infoframe.c b/lib/igt_infoframe.c
new file mode 100644
index 00000000..2e14fe70
--- /dev/null
+++ b/lib/igt_infoframe.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * 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: Simon Ser <simon.ser@intel.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "igt_core.h"
+#include "igt_infoframe.h"
+
+/**
+ * SECTION:igt_infoframe
+ * @short_description: InfoFrame parsing library
+ * @title: InfoFrame
+ * @include: igt_infoframe.h
+ *
+ * This library provides helpers to parse InfoFrames as defined in CEA-861-D
+ * section 6.
+ */
+
+static const int sampling_freqs[] = {
+ -1, /* refer to stream header */
+ 33000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+};
+
+static const size_t sampling_freqs_len = sizeof(sampling_freqs) / sizeof(sampling_freqs[0]);
+
+static const int sample_sizes[] = {
+ -1, /* refer to stream header */
+ 16,
+ 20,
+ 24,
+};
+
+static const size_t sample_sizes_len = sizeof(sample_sizes) / sizeof(sample_sizes[0]);
+
+bool infoframe_avi_parse(struct infoframe_avi *infoframe, int version,
+ const uint8_t *buf, size_t buf_size)
+{
+ memset(infoframe, 0, sizeof(*infoframe));
+
+ switch (version) {
+ case 2:
+ case 3:
+ case 4:
+ break; /* supported */
+ default:
+ igt_debug("Unsuppported AVI InfoFrame version: %d\n", version);
+ return false;
+ }
+
+ if (buf_size < 13)
+ return false;
+
+ infoframe->rgb_ycbcr = buf[0] >> 5;
+ infoframe->scan = buf[0] & 0x3;
+
+ infoframe->colorimetry = buf[1] >> 6;
+ infoframe->picture_aspect_ratio = (buf[1] >> 4) & 0x3;
+ infoframe->active_aspect_ratio = buf[1] & 0xF;
+ infoframe->vic = buf[3];
+
+ return true;
+}
+
+bool infoframe_audio_parse(struct infoframe_audio *infoframe, int version,
+ const uint8_t *buf, size_t buf_size)
+{
+ int channel_count;
+ size_t sampling_freq_idx, sample_size_idx;
+
+ memset(infoframe, 0, sizeof(*infoframe));
+
+ if (version != 1 || buf_size < 5)
+ return false;
+
+ infoframe->coding_type = buf[0] >> 4;
+
+ channel_count = buf[0] & 0x7;
+ if (channel_count == 0)
+ infoframe->channel_count = -1;
+ else
+ infoframe->channel_count = channel_count + 1;
+
+ sampling_freq_idx = (buf[1] >> 2) & 0x7;
+ if (sampling_freq_idx >= sampling_freqs_len)
+ return false;
+ infoframe->sampling_freq = sampling_freqs[sampling_freq_idx];
+
+ sample_size_idx = buf[1] & 0x3;
+ if (sample_size_idx >= sample_sizes_len)
+ return false;
+ infoframe->sample_size = sample_sizes[sample_size_idx];
+
+ return true;
+}
diff --git a/lib/igt_infoframe.h b/lib/igt_infoframe.h
new file mode 100644
index 00000000..eae251ea
--- /dev/null
+++ b/lib/igt_infoframe.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * 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: Simon Ser <simon.ser@intel.com>
+ */
+
+#ifndef IGT_INFOFRAME_H
+#define IGT_INFOFRAME_H
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+enum infoframe_avi_rgb_ycbcr {
+ INFOFRAME_AVI_RGB = 0,
+ INFOFRAME_AVI_YCBCR422 = 1,
+ INFOFRAME_AVI_YCBCR444 = 2,
+ INFOFRAME_AVI_YCBCR420 = 3,
+ INFOFRAME_AVI_IDO_DEFINED = 7,
+};
+
+enum infoframe_avi_scan {
+ INFOFRAME_AVI_SCAN_UNSPECIFIED = 0,
+ INFOFRAME_AVI_OVERSCAN = 1,
+ INFOFRAME_AVI_UNDERSCAN = 2,
+};
+
+enum infoframe_avi_colorimetry {
+ INFOFRAME_AVI_COLORIMETRY_UNSPECIFIED = 0,
+ INFOFRAME_AVI_SMPTE_170M = 1,
+ INFOFRAME_AVI_ITUR_BT709 = 2,
+ INFOFRAME_AVI_COLORIMETRY_EXTENDED = 3,
+};
+
+enum infoframe_avi_picture_aspect_ratio {
+ INFOFRAME_AVI_PIC_AR_UNSPECIFIED = 0,
+ INFOFRAME_AVI_PIC_AR_4_3 = 1,
+ INFOFRAME_AVI_PIC_AR_16_9 = 2,
+};
+
+enum infoframe_avi_active_aspect_ratio {
+ INFOFRAME_AVI_ACT_AR_PIC = 8, /* same as picture aspect ratio */
+ INFOFRAME_AVI_ACT_AR_4_3 = 9,
+ INFOFRAME_AVI_ACT_AR_16_9 = 10,
+ INFOFRAME_AVI_ACT_AR_14_9 = 11,
+};
+
+#define INFOFRAME_AVI_VIC_UNSPECIFIED 0
+
+struct infoframe_avi {
+ enum infoframe_avi_rgb_ycbcr rgb_ycbcr;
+ enum infoframe_avi_scan scan;
+ enum infoframe_avi_colorimetry colorimetry;
+ enum infoframe_avi_picture_aspect_ratio picture_aspect_ratio;
+ enum infoframe_avi_active_aspect_ratio active_aspect_ratio;
+ uint8_t vic; /* Video Identification Code */
+ /* TODO: remaining fields */
+};
+
+enum infoframe_audio_coding_type {
+ INFOFRAME_AUDIO_CT_UNSPECIFIED = 0, /* refer to stream header */
+ INFOFRAME_AUDIO_CT_PCM = 1, /* IEC 60958 PCM */
+ INFOFRAME_AUDIO_CT_AC3 = 2,
+ INFOFRAME_AUDIO_CT_MPEG1 = 3,
+ INFOFRAME_AUDIO_CT_MP3 = 4,
+ INFOFRAME_AUDIO_CT_MPEG2 = 5,
+ INFOFRAME_AUDIO_CT_AAC = 6,
+ INFOFRAME_AUDIO_CT_DTS = 7,
+ INFOFRAME_AUDIO_CT_ATRAC = 8,
+ INFOFRAME_AUDIO_CT_ONE_BIT = 9,
+ INFOFRAME_AUDIO_CT_DOLBY = 10, /* Dolby Digital + */
+ INFOFRAME_AUDIO_CT_DTS_HD = 11,
+ INFOFRAME_AUDIO_CT_MAT = 12,
+ INFOFRAME_AUDIO_CT_DST = 13,
+ INFOFRAME_AUDIO_CT_WMA_PRO = 14,
+};
+
+struct infoframe_audio {
+ enum infoframe_audio_coding_type coding_type;
+ int channel_count; /* -1 if unspecified */
+ int sampling_freq; /* in Hz, -1 if unspecified */
+ int sample_size; /* in bits, -1 if unspecified */
+ /* TODO: speaker allocation */
+};
+
+bool infoframe_avi_parse(struct infoframe_avi *infoframe, int version,
+ const uint8_t *buf, size_t buf_size);
+bool infoframe_audio_parse(struct infoframe_audio *infoframe, int version,
+ const uint8_t *buf, size_t buf_size);
+
+#endif
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index 175e71c3..17a7d2b6 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -100,7 +100,7 @@ static int forced_connectors_device[MAX_CONNECTORS + 1];
*
* Returns: a basic edid block
*/
-const unsigned char *igt_kms_get_base_edid(void)
+const struct edid *igt_kms_get_base_edid(void)
{
static struct edid edid;
drmModeModeInfo mode = {};
@@ -119,7 +119,7 @@ const unsigned char *igt_kms_get_base_edid(void)
edid_init_with_mode(&edid, &mode);
edid_update_checksum(&edid);
- return (unsigned char *) &edid;
+ return &edid;
}
/**
@@ -136,7 +136,7 @@ const unsigned char *igt_kms_get_base_edid(void)
*
* Returns: an alternate edid block
*/
-const unsigned char *igt_kms_get_alt_edid(void)
+const struct edid *igt_kms_get_alt_edid(void)
{
static struct edid edid;
drmModeModeInfo mode = {};
@@ -155,13 +155,13 @@ const unsigned char *igt_kms_get_alt_edid(void)
edid_init_with_mode(&edid, &mode);
edid_update_checksum(&edid);
- return (unsigned char *) &edid;
+ return &edid;
}
-#define AUDIO_EDID_LENGTH (2 * EDID_LENGTH)
+#define AUDIO_EDID_SIZE (2 * EDID_BLOCK_SIZE)
-static void
-generate_audio_edid(unsigned char raw_edid[static AUDIO_EDID_LENGTH],
+static const struct edid *
+generate_audio_edid(unsigned char raw_edid[static AUDIO_EDID_SIZE],
bool with_vsdb, struct cea_sad *sad,
struct cea_speaker_alloc *speaker_alloc)
{
@@ -205,14 +205,15 @@ generate_audio_edid(unsigned char raw_edid[static AUDIO_EDID_LENGTH],
edid_ext_set_cea(edid_ext, cea_data_size, 0, EDID_CEA_BASIC_AUDIO);
edid_update_checksum(edid);
- edid_ext_update_cea_checksum(edid_ext);
+
+ return edid;
}
-const unsigned char *igt_kms_get_hdmi_audio_edid(void)
+const struct edid *igt_kms_get_hdmi_audio_edid(void)
{
int channels;
uint8_t sampling_rates, sample_sizes;
- static unsigned char raw_edid[AUDIO_EDID_LENGTH] = {0};
+ static unsigned char raw_edid[AUDIO_EDID_SIZE] = {0};
struct cea_sad sad = {0};
struct cea_speaker_alloc speaker_alloc = {0};
@@ -229,16 +230,14 @@ const unsigned char *igt_kms_get_hdmi_audio_edid(void)
/* Initialize the Speaker Allocation Data */
speaker_alloc.speakers = CEA_SPEAKER_FRONT_LEFT_RIGHT_CENTER;
- generate_audio_edid(raw_edid, true, &sad, &speaker_alloc);
-
- return raw_edid;
+ return generate_audio_edid(raw_edid, true, &sad, &speaker_alloc);
}
-const unsigned char *igt_kms_get_dp_audio_edid(void)
+const struct edid *igt_kms_get_dp_audio_edid(void)
{
int channels;
uint8_t sampling_rates, sample_sizes;
- static unsigned char raw_edid[AUDIO_EDID_LENGTH] = {0};
+ static unsigned char raw_edid[AUDIO_EDID_SIZE] = {0};
struct cea_sad sad = {0};
struct cea_speaker_alloc speaker_alloc = {0};
@@ -255,9 +254,7 @@ const unsigned char *igt_kms_get_dp_audio_edid(void)
/* Initialize the Speaker Allocation Data */
speaker_alloc.speakers = CEA_SPEAKER_FRONT_LEFT_RIGHT_CENTER;
- generate_audio_edid(raw_edid, false, &sad, &speaker_alloc);
-
- return raw_edid;
+ return generate_audio_edid(raw_edid, false, &sad, &speaker_alloc);
}
static const uint8_t edid_4k_svds[] = {
@@ -268,7 +265,7 @@ static const uint8_t edid_4k_svds[] = {
19, /* 720p @ 50Hz */
};
-const unsigned char *igt_kms_get_4k_edid(void)
+const struct edid *igt_kms_get_4k_edid(void)
{
static unsigned char raw_edid[256] = {0};
struct edid *edid;
@@ -316,11 +313,11 @@ const unsigned char *igt_kms_get_4k_edid(void)
edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
edid_update_checksum(edid);
- edid_ext_update_cea_checksum(edid_ext);
- return raw_edid;
+
+ return edid;
}
-const unsigned char *igt_kms_get_3d_edid(void)
+const struct edid *igt_kms_get_3d_edid(void)
{
static unsigned char raw_edid[256] = {0};
struct edid *edid;
@@ -367,8 +364,8 @@ const unsigned char *igt_kms_get_3d_edid(void)
edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
edid_update_checksum(edid);
- edid_ext_update_cea_checksum(edid_ext);
- return raw_edid;
+
+ return edid;
}
const char * const igt_plane_prop_names[IGT_NUM_PLANE_PROPS] = {
@@ -413,6 +410,8 @@ const char * const igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
[IGT_CONNECTOR_BROADCAST_RGB] = "Broadcast RGB",
[IGT_CONNECTOR_CONTENT_PROTECTION] = "Content Protection",
[IGT_CONNECTOR_VRR_CAPABLE] = "vrr_capable",
+ [IGT_CONNECTOR_HDCP_CONTENT_TYPE] = "HDCP Content Type",
+ [IGT_CONNECTOR_LINK_STATUS] = "link-status",
};
/*
@@ -1084,7 +1083,7 @@ bool kmstest_force_connector(int drm_fd, drmModeConnector *connector,
* If @edid is NULL, the forced EDID will be removed.
*/
void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
- const unsigned char *edid)
+ const struct edid *edid)
{
char *path;
int debugfs_fd, ret;
@@ -1101,7 +1100,7 @@ void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
ret = write(debugfs_fd, "reset", 5);
else
ret = write(debugfs_fd, edid,
- edid_get_size((struct edid *) edid));
+ edid_get_size(edid));
close(debugfs_fd);
/* To allow callers to always use GetConnectorCurrent we need to force a
@@ -1858,6 +1857,10 @@ static void igt_output_reset(igt_output_t *output)
if (igt_output_has_prop(output, IGT_CONNECTOR_BROADCAST_RGB))
igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB,
BROADCAST_RGB_FULL);
+
+ if (igt_output_has_prop(output, IGT_CONNECTOR_CONTENT_PROTECTION))
+ igt_output_set_prop_enum(output, IGT_CONNECTOR_CONTENT_PROTECTION,
+ "Undesired");
}
/**
@@ -1870,6 +1873,7 @@ static void igt_output_reset(igt_output_t *output)
* For outputs:
* - %IGT_CONNECTOR_CRTC_ID
* - %IGT_CONNECTOR_BROADCAST_RGB (if applicable)
+ * %IGT_CONNECTOR_CONTENT_PROTECTION (if applicable)
* - igt_output_override_mode() to default.
*
* For pipes:
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index 0486737b..56481fd1 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -123,6 +123,8 @@ enum igt_atomic_connector_properties {
IGT_CONNECTOR_BROADCAST_RGB,
IGT_CONNECTOR_CONTENT_PROTECTION,
IGT_CONNECTOR_VRR_CAPABLE,
+ IGT_CONNECTOR_HDCP_CONTENT_TYPE,
+ IGT_CONNECTOR_LINK_STATUS,
IGT_NUM_CONNECTOR_PROPS
};
@@ -191,11 +193,12 @@ enum intel_broadcast_rgb_mode {
BROADCAST_RGB_16_235
};
+struct edid;
bool kmstest_force_connector(int fd, drmModeConnector *connector,
enum kmstest_force_connector_state state);
void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
- const unsigned char *edid);
+ const struct edid *edid);
bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
drmModeModeInfo *mode);
@@ -753,16 +756,12 @@ void igt_reset_connectors(void);
uint32_t kmstest_get_vbl_flag(uint32_t pipe_id);
-struct cea_sad;
-struct cea_speaker_alloc;
-
-#define EDID_LENGTH 128
-const unsigned char *igt_kms_get_base_edid(void);
-const unsigned char *igt_kms_get_alt_edid(void);
-const unsigned char *igt_kms_get_hdmi_audio_edid(void);
-const unsigned char *igt_kms_get_dp_audio_edid(void);
-const unsigned char *igt_kms_get_4k_edid(void);
-const unsigned char *igt_kms_get_3d_edid(void);
+const struct edid *igt_kms_get_base_edid(void);
+const struct edid *igt_kms_get_alt_edid(void);
+const struct edid *igt_kms_get_hdmi_audio_edid(void);
+const struct edid *igt_kms_get_dp_audio_edid(void);
+const struct edid *igt_kms_get_4k_edid(void);
+const struct edid *igt_kms_get_3d_edid(void);
struct udev_monitor *igt_watch_hotplug(void);
bool igt_hotplug_detected(struct udev_monitor *mon,
diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h
index 781486d0..2bd57f4f 100644
--- a/lib/intel_chipset.h
+++ b/lib/intel_chipset.h
@@ -162,11 +162,12 @@ void intel_check_pch(void);
#define IS_HASWELL(devid) (intel_get_device_info(devid)->is_haswell)
#define IS_BROADWELL(devid) (intel_get_device_info(devid)->is_broadwell)
#define IS_CHERRYVIEW(devid) (intel_get_device_info(devid)->is_cherryview)
-#define IS_KABYLAKE(devid) (intel_get_device_info(devid)->is_kabylake)
#define IS_SKYLAKE(devid) (intel_get_device_info(devid)->is_skylake)
#define IS_BROXTON(devid) (intel_get_device_info(devid)->is_broxton)
+#define IS_KABYLAKE(devid) (intel_get_device_info(devid)->is_kabylake)
#define IS_GEMINILAKE(devid) (intel_get_device_info(devid)->is_geminilake)
#define IS_COFFEELAKE(devid) (intel_get_device_info(devid)->is_coffeelake)
+#define IS_COMETLAKE(devid) (intel_get_device_info(devid)->is_cometlake)
#define IS_CANNONLAKE(devid) (intel_get_device_info(devid)->is_cannonlake)
#define IS_ICELAKE(devid) (intel_get_device_info(devid)->is_icelake)
#define IS_TIGERLAKE(devid) (intel_get_device_info(devid)->is_tigerlake)
diff --git a/lib/meson.build b/lib/meson.build
index 157624e7..221ae28c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -61,6 +61,7 @@ lib_sources = [
'igt_amd.c',
'igt_edid.c',
'igt_eld.c',
+ 'igt_infoframe.c',
]
lib_deps = [
diff --git a/lib/sw_sync.c b/lib/sw_sync.c
index f2086033..d671923c 100644
--- a/lib/sw_sync.c
+++ b/lib/sw_sync.c
@@ -206,19 +206,12 @@ int sync_fence_count_status(int fd, int status)
int sync_fence_status(int fence)
{
- struct sync_fence_info fence_info;
- struct sync_file_info file_info = {
- .sync_fence_info = to_user_pointer(&fence_info),
- .num_fences = 1,
- };
+ struct sync_file_info info = { };
- if (ioctl(fence, SYNC_IOC_FILE_INFO, &file_info))
+ if (ioctl(fence, SYNC_IOC_FILE_INFO, &info))
return -errno;
- if (file_info.num_fences != 1)
- return -EINVAL;
-
- return fence_info.status;
+ return info.status;
}
static void modprobe(const char *driver)
diff --git a/lib/tests/igt_audio.c b/lib/tests/igt_audio.c
index a2d57fb8..c0727673 100644
--- a/lib/tests/igt_audio.c
+++ b/lib/tests/igt_audio.c
@@ -176,7 +176,7 @@ static void test_signal_detect_phaseshift(struct audio_signal *signal)
igt_main
{
- struct audio_signal *signal;
+ struct audio_signal *signal = NULL;
int ret;
size_t i;
diff --git a/lib/tests/igt_edid.c b/lib/tests/igt_edid.c
index fc98f1bb..8474d29e 100644
--- a/lib/tests/igt_edid.c
+++ b/lib/tests/igt_edid.c
@@ -57,14 +57,14 @@ static bool edid_block_checksum(const unsigned char *raw_edid)
size_t i;
unsigned char csum = 0;
- for (i = 0; i < EDID_LENGTH; i++) {
+ for (i = 0; i < EDID_BLOCK_SIZE; i++) {
csum += raw_edid[i];
}
return csum == 0;
}
-typedef const unsigned char *(*get_edid_func)(void);
+typedef const struct edid *(*get_edid_func)(void);
igt_simple_main
{
@@ -80,23 +80,28 @@ igt_simple_main
{ "3d", igt_kms_get_3d_edid, 1 },
{0},
}, *f;
- const unsigned char *edid;
+ const struct edid *edid;
+ const uint8_t *raw_edid, *raw_block;
size_t i;
for (f = funcs; f->f; f++) {
edid = f->f();
+ raw_edid = (uint8_t *) edid;
- igt_assert_f(edid_header_is_valid(edid),
+ igt_assert_f(edid_header_is_valid(raw_edid),
"invalid header on %s EDID", f->desc);
/* check base edid block */
- igt_assert_f(edid_block_checksum(edid),
+ igt_assert_f(edid_block_checksum(raw_edid),
"checksum failed on %s EDID", f->desc);
/* check extension blocks, if any */
- igt_assert_f(edid[126] == f->exts,
+ igt_assert_f(raw_edid[126] == f->exts,
"unexpected number of extensions on %s EDID",
f->desc);
- for (i = 0; i < f->exts; i++)
- igt_assert_f(edid_block_checksum(edid + (i + 1) * EDID_LENGTH),
- "CEA block checksum failed on %s EDID", f->desc);
+ for (i = 0; i < f->exts; i++) {
+ raw_block = raw_edid + (i + 1) * EDID_BLOCK_SIZE;
+ igt_assert_f(edid_block_checksum(raw_block),
+ "CEA block checksum failed on %s EDID",
+ f->desc);
+ }
}
}
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 250dbd33..c02e4d94 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -20,6 +20,7 @@ TESTS_progs = \
core_getversion \
core_setmaster_vs_auth \
debugfs_test \
+ dmabuf \
drm_import_export \
drm_mm \
drm_read \
@@ -63,6 +64,7 @@ TESTS_progs = \
kms_plane_lowres \
kms_plane_multiple \
kms_plane_scaling \
+ kms_prime \
kms_prop_blob \
kms_properties \
kms_psr \
diff --git a/tests/debugfs_test.c b/tests/debugfs_test.c
index 6a87d90a..6d1757c5 100644
--- a/tests/debugfs_test.c
+++ b/tests/debugfs_test.c
@@ -167,27 +167,6 @@ igt_main
igt_subtest_group
kms_tests(fd, debugfs);
- igt_subtest("emon_crash") {
- int i;
- /*
- * This check if we can crash the kernel with
- * segmentation-fault by reading
- * /sys/kernel/debug/dri/0/i915_emon_status too quickly
- */
- for (i = 0; i < 1000; i++) {
- char *buf = igt_sysfs_get(debugfs,
- "i915_emon_status");
-
- igt_skip_on_f(!buf && !i, "i915_emon_status could not be read\n");
-
- igt_assert(buf);
- free(buf);
- }
-
- /* If we got here, we haven't crashed */
- igt_success();
- }
-
igt_fixture {
close(debugfs);
close(fd);
diff --git a/tests/dmabuf.c b/tests/dmabuf.c
new file mode 100644
index 00000000..a72cf3be
--- /dev/null
+++ b/tests/dmabuf.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * 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.
+ */
+
+#include "igt.h"
+#include "igt_kmod.h"
+
+IGT_TEST_DESCRIPTION("Kernel selftests for the dmabuf API");
+
+igt_main
+{
+ igt_kselftests("dmabuf_selftests", NULL, NULL, NULL);
+}
diff --git a/tests/i915/gem_concurrent_all.c b/tests/i915/gem_concurrent_all.c
index 3ddaab82..266995d1 100644
--- a/tests/i915/gem_concurrent_all.c
+++ b/tests/i915/gem_concurrent_all.c
@@ -968,8 +968,6 @@ static void do_basic0(struct buffers *buffers,
do_copy do_copy_func,
do_hang do_hang_func)
{
- gem_quiescent_gpu(fd);
-
buffers->mode->set_bo(buffers, buffers->src[0], 0xdeadbeef);
for (int i = 0; i < buffers->count; i++) {
igt_hang_t hang = do_hang_func();
@@ -985,8 +983,6 @@ static void do_basic1(struct buffers *buffers,
do_copy do_copy_func,
do_hang do_hang_func)
{
- gem_quiescent_gpu(fd);
-
for (int i = 0; i < buffers->count; i++) {
igt_hang_t hang = do_hang_func();
@@ -1007,8 +1003,6 @@ static void do_basicN(struct buffers *buffers,
{
igt_hang_t hang;
- gem_quiescent_gpu(fd);
-
for (int i = 0; i < buffers->count; i++) {
buffers->mode->set_bo(buffers, buffers->src[i], i);
buffers->mode->set_bo(buffers, buffers->dst[i], ~i);
@@ -1034,7 +1028,6 @@ static void do_overwrite_source(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = 0; i < buffers->count; i++) {
buffers->mode->set_bo(buffers, buffers->src[i], i);
buffers->mode->set_bo(buffers, buffers->dst[i], ~i);
@@ -1058,7 +1051,6 @@ static void do_overwrite_source_read(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = 0; i < half; i++) {
buffers->mode->set_bo(buffers, buffers->src[i], i);
buffers->mode->set_bo(buffers, buffers->dst[i], ~i);
@@ -1102,7 +1094,6 @@ static void do_overwrite_source__rev(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = 0; i < buffers->count; i++) {
buffers->mode->set_bo(buffers, buffers->src[i], i);
buffers->mode->set_bo(buffers, buffers->dst[i], ~i);
@@ -1123,7 +1114,6 @@ static void do_overwrite_source__one(struct buffers *buffers,
{
igt_hang_t hang;
- gem_quiescent_gpu(fd);
buffers->mode->set_bo(buffers, buffers->src[0], 0);
buffers->mode->set_bo(buffers, buffers->dst[0], ~0);
do_copy_func(buffers, buffers->dst[0], buffers->src[0]);
@@ -1142,7 +1132,6 @@ static void do_intermix(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = 0; i < buffers->count; i++) {
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef^~i);
buffers->mode->set_bo(buffers, buffers->dst[i], i);
@@ -1196,7 +1185,6 @@ static void do_early_read(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef);
for (i = 0; i < buffers->count; i++)
@@ -1214,7 +1202,6 @@ static void do_read_read_bcs(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef ^ i);
for (i = 0; i < buffers->count; i++) {
@@ -1235,7 +1222,6 @@ static void do_write_read_bcs(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef ^ i);
for (i = 0; i < buffers->count; i++) {
@@ -1255,7 +1241,6 @@ static void do_read_read_rcs(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef ^ i);
for (i = 0; i < buffers->count; i++) {
@@ -1276,7 +1261,6 @@ static void do_write_read_rcs(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xdeadbeef ^ i);
for (i = 0; i < buffers->count; i++) {
@@ -1296,7 +1280,6 @@ static void do_gpu_read_after_write(struct buffers *buffers,
igt_hang_t hang;
int i;
- gem_quiescent_gpu(fd);
for (i = buffers->count; i--; )
buffers->mode->set_bo(buffers, buffers->src[i], 0xabcdabcd);
for (i = 0; i < buffers->count; i++)
diff --git a/tests/i915/gem_ctx_engines.c b/tests/i915/gem_ctx_engines.c
index 8c66fb26..1e82e51e 100644
--- a/tests/i915/gem_ctx_engines.c
+++ b/tests/i915/gem_ctx_engines.c
@@ -405,6 +405,14 @@ static void execute_allforone(int i915)
gem_context_destroy(i915, param.ctx_id);
}
+static uint32_t read_result(int timeline, uint32_t *map, int idx)
+{
+ sw_sync_timeline_inc(timeline, 1);
+ while (!READ_ONCE(map[idx]))
+ ;
+ return map[idx];
+}
+
static void independent(int i915)
{
#define RCS_TIMESTAMP (0x2000 + 0x358)
@@ -423,6 +431,7 @@ static void independent(int i915)
uint32_t last, *map;
igt_require(gen >= 6); /* No per-engine TIMESTAMP on older gen */
+ igt_require(gem_scheduler_enabled(i915));
{
struct drm_i915_gem_execbuffer2 execbuf = {
@@ -438,6 +447,12 @@ static void independent(int i915)
memset(&engines, 0, sizeof(engines)); /* All rcs0 */
gem_context_set_param(i915, &param);
+ gem_set_caching(i915, results.handle, I915_CACHING_CACHED);
+ map = gem_mmap__cpu(i915, results.handle, 0, 4096, PROT_READ);
+ gem_set_domain(i915, results.handle,
+ I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+ memset(map, 0, 4096);
+
for (int i = 0; i < I915_EXEC_RING_MASK + 1; i++) {
struct drm_i915_gem_exec_object2 obj[2] = {
results, /* write hazard lies! */
@@ -472,21 +487,21 @@ static void independent(int i915)
gem_close(i915, obj[1].handle);
close(execbuf.rsvd2);
}
- close(timeline);
- gem_sync(i915, results.handle);
-
- map = gem_mmap__cpu(i915, results.handle, 0, 4096, PROT_READ);
- gem_set_domain(i915, results.handle, I915_GEM_DOMAIN_CPU, 0);
- gem_close(i915, results.handle);
- last = map[0];
+ last = read_result(timeline, map, 0);
for (int i = 1; i < I915_EXEC_RING_MASK + 1; i++) {
- igt_assert_f((map[i] - last) > 0,
- "Engine instance [%d] executed too late\n", i);
- last = map[i];
+ uint32_t t = read_result(timeline, map, i);
+ igt_assert_f(t - last > 0,
+ "Engine instance [%d] executed too late, previous timestamp %08x, now %08x\n",
+ i, last, t);
+ last = t;
}
munmap(map, 4096);
+ close(timeline);
+ gem_sync(i915, results.handle);
+ gem_close(i915, results.handle);
+
gem_context_destroy(i915, param.ctx_id);
}
@@ -500,6 +515,8 @@ igt_main
gem_require_contexts(i915);
igt_require(has_context_engines(i915));
+
+ igt_fork_hang_detector(i915);
}
igt_subtest("invalid-engines")
@@ -519,4 +536,7 @@ igt_main
igt_subtest("independent")
independent(i915);
+
+ igt_fixture
+ igt_stop_hang_detector();
}
diff --git a/tests/i915/gem_ctx_shared.c b/tests/i915/gem_ctx_shared.c
index 4b1020b9..b073bdfc 100644
--- a/tests/i915/gem_ctx_shared.c
+++ b/tests/i915/gem_ctx_shared.c
@@ -192,7 +192,8 @@ static void exec_shared_gtt(int i915, unsigned int ring)
.flags = ring,
};
uint32_t scratch, *s;
- uint32_t batch[16];
+ uint32_t batch, cs[16];
+ uint64_t offset;
int i;
gem_require_ring(i915, ring);
@@ -207,54 +208,62 @@ static void exec_shared_gtt(int i915, unsigned int ring)
obj.flags |= EXEC_OBJECT_PINNED; /* reuse this address */
scratch = gem_create(i915, 4096);
- s = gem_mmap__cpu(i915, scratch, 0, 4096, PROT_WRITE);
+ s = gem_mmap__wc(i915, scratch, 0, 4096, PROT_WRITE);
- gem_set_domain(i915, scratch, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
- *s = bbe;
+ gem_set_domain(i915, scratch, I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC);
+ s[0] = bbe;
+ s[64] = bbe;
/* Load object into place in the GTT */
obj.handle = scratch;
gem_execbuf(i915, &execbuf);
+ offset = obj.offset;
/* Presume nothing causes an eviction in the meantime! */
- obj.handle = gem_create(i915, 4096);
+ batch = gem_create(i915, 4096);
i = 0;
- batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
+ cs[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
if (gen >= 8) {
- batch[++i] = obj.offset;
- batch[++i] = 0;
+ cs[++i] = obj.offset;
+ cs[++i] = obj.offset >> 32;
} else if (gen >= 4) {
- batch[++i] = 0;
- batch[++i] = obj.offset;
+ cs[++i] = 0;
+ cs[++i] = obj.offset;
} else {
- batch[i]--;
- batch[++i] = obj.offset;
+ cs[i]--;
+ cs[++i] = obj.offset;
}
- batch[++i] = 0xc0ffee;
- batch[++i] = bbe;
- gem_write(i915, obj.handle, 0, batch, sizeof(batch));
+ cs[++i] = 0xc0ffee;
+ cs[++i] = bbe;
+ gem_write(i915, batch, 0, cs, sizeof(cs));
+ obj.handle = batch;
obj.offset += 8192; /* make sure we don't cause an eviction! */
execbuf.rsvd1 = gem_context_clone(i915, 0, I915_CONTEXT_CLONE_VM, 0);
if (gen > 3 && gen < 6)
execbuf.flags |= I915_EXEC_SECURE;
+ gem_execbuf(i915, &execbuf);
+ /* Check the scratch didn't move */
+ obj.handle = scratch;
+ obj.offset = -1;
+ obj.flags &= ~EXEC_OBJECT_PINNED;
+ execbuf.batch_start_offset = 64 * sizeof(s[0]);
gem_execbuf(i915, &execbuf);
+ igt_assert_eq_u64(obj.offset, offset);
gem_context_destroy(i915, execbuf.rsvd1);
- gem_sync(i915, obj.handle); /* write hazard lies */
- gem_close(i915, obj.handle);
+
+ gem_sync(i915, batch); /* write hazard lies */
+ gem_close(i915, batch);
/*
* If we created the new context with the old GTT, the write
* into the stale location of scratch will have landed in the right
* object. Otherwise, it should read the previous value of
* MI_BATCH_BUFFER_END.
- *
- * Setting .write = CPU to paper over our write hazard lies above.
*/
- gem_set_domain(i915, scratch, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
igt_assert_eq_u32(*s, 0xc0ffee);
munmap(s, 4096);
diff --git a/tests/i915/gem_eio.c b/tests/i915/gem_eio.c
index 4d7362d8..9b086a03 100644
--- a/tests/i915/gem_eio.c
+++ b/tests/i915/gem_eio.c
@@ -559,6 +559,7 @@ static void test_inflight_contexts(int fd, unsigned int wait)
const uint32_t bbe = MI_BATCH_BUFFER_END;
struct drm_i915_gem_exec_object2 obj[2];
struct drm_i915_gem_execbuffer2 execbuf;
+ unsigned int count;
igt_spin_t *hang;
uint32_t ctx[64];
int fence[64];
@@ -587,16 +588,19 @@ static void test_inflight_contexts(int fd, unsigned int wait)
execbuf.buffer_count = 2;
execbuf.flags = engine | I915_EXEC_FENCE_OUT;
+ count = 0;
for (unsigned int n = 0; n < ARRAY_SIZE(fence); n++) {
execbuf.rsvd1 = ctx[n];
- gem_execbuf_wr(fd, &execbuf);
+ if (__gem_execbuf_wr(fd, &execbuf))
+ break; /* small shared ring */
fence[n] = execbuf.rsvd2 >> 32;
igt_assert(fence[n] != -1);
+ count++;
}
check_wait(fd, obj[1].handle, wait, NULL);
- for (unsigned int n = 0; n < ARRAY_SIZE(fence); n++) {
+ for (unsigned int n = 0; n < count; n++) {
igt_assert_eq(sync_fence_status(fence[n]), -EIO);
close(fence[n]);
}
@@ -730,6 +734,11 @@ static void reset_stress(int fd, uint32_t ctx0,
.flags = engine,
};
igt_stats_t stats;
+ int max;
+
+ max = gem_measure_ring_inflight(fd, engine, 0);
+ max = max / 2 - 1; /* assume !execlists and a shared ring */
+ igt_require(max > 0);
gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
@@ -751,11 +760,11 @@ static void reset_stress(int fd, uint32_t ctx0,
hang = spin_sync(fd, ctx0, engine);
execbuf.rsvd1 = ctx;
- for (i = 0; i < 10; i++)
+ for (i = 0; i < max; i++)
gem_execbuf(fd, &execbuf);
execbuf.rsvd1 = ctx0;
- for (i = 0; i < 10; i++)
+ for (i = 0; i < max; i++)
gem_execbuf(fd, &execbuf);
/* Wedge after a small delay. */
@@ -773,11 +782,11 @@ static void reset_stress(int fd, uint32_t ctx0,
* both contexts.
*/
execbuf.rsvd1 = ctx;
- for (i = 0; i < 5; i++)
+ for (i = 0; i < max; i++)
gem_execbuf(fd, &execbuf);
execbuf.rsvd1 = ctx0;
- for (i = 0; i < 5; i++)
+ for (i = 0; i < max; i++)
gem_execbuf(fd, &execbuf);
gem_sync(fd, obj.handle);
diff --git a/tests/i915/gem_exec_fence.c b/tests/i915/gem_exec_fence.c
index 0befb54f..20718292 100644
--- a/tests/i915/gem_exec_fence.c
+++ b/tests/i915/gem_exec_fence.c
@@ -274,7 +274,7 @@ static void test_fence_busy_all(int fd, unsigned flags)
if (all < 0) {
all = fence;
- break;
+ continue;
}
new = sync_fence_merge(all, fence);
diff --git a/tests/i915/gem_exec_schedule.c b/tests/i915/gem_exec_schedule.c
index 7b418622..05810210 100644
--- a/tests/i915/gem_exec_schedule.c
+++ b/tests/i915/gem_exec_schedule.c
@@ -164,8 +164,13 @@ static uint32_t create_highest_priority(int fd)
static void unplug_show_queue(int fd, struct igt_cork *c, unsigned int engine)
{
igt_spin_t *spin[MAX_ELSP_QLEN];
+ int max = MAX_ELSP_QLEN;
- for (int n = 0; n < ARRAY_SIZE(spin); n++) {
+ /* If no scheduler, all batches are emitted in submission order */
+ if (!gem_scheduler_enabled(fd))
+ max = 1;
+
+ for (int n = 0; n < max; n++) {
const struct igt_spin_factory opts = {
.ctx = create_highest_priority(fd),
.engine = engine,
@@ -177,7 +182,7 @@ static void unplug_show_queue(int fd, struct igt_cork *c, unsigned int engine)
igt_cork_unplug(c); /* batches will now be queued on the engine */
igt_debugfs_dump(fd, "i915_engine_info");
- for (int n = 0; n < ARRAY_SIZE(spin); n++)
+ for (int n = 0; n < max; n++)
igt_spin_free(fd, spin[n]);
}
@@ -282,9 +287,11 @@ static void smoketest(int fd, unsigned ring, unsigned timeout)
nengine = 0;
if (ring == ALL_ENGINES) {
for_each_physical_engine(fd, engine)
- engines[nengine++] = engine;
+ if (gem_can_store_dword(fd, engine))
+ engines[nengine++] = engine;
} else {
- engines[nengine++] = ring;
+ if (gem_can_store_dword(fd, ring))
+ engines[nengine++] = ring;
}
igt_require(nengine);
@@ -1774,9 +1781,6 @@ igt_main
igt_fixture {
igt_require(gem_scheduler_enabled(fd));
igt_require(gem_scheduler_has_ctx_priority(fd));
-
- /* need separate rings */
- igt_require(gem_has_execlists(fd));
}
for (e = intel_execution_engines; e->name; e++) {
diff --git a/tests/i915/gem_mmap_gtt.c b/tests/i915/gem_mmap_gtt.c
index 6f3a9c36..8eff9185 100644
--- a/tests/i915/gem_mmap_gtt.c
+++ b/tests/i915/gem_mmap_gtt.c
@@ -323,6 +323,44 @@ test_pf_nonblock(int i915)
}
static void
+test_isolation(int i915)
+{
+ struct drm_i915_gem_mmap_gtt mmap_arg;
+ int A = gem_reopen_driver(i915);
+ int B = gem_reopen_driver(i915);
+ uint64_t offset_a, offset_b;
+ uint32_t a, b;
+ void *ptr;
+
+ a = gem_create(A, 4096);
+ b = gem_open(B, gem_flink(A, a));
+
+ mmap_arg.handle = a;
+ do_ioctl(A, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg);
+ offset_a = mmap_arg.offset;
+
+ mmap_arg.handle = b;
+ do_ioctl(B, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg);
+ offset_b = mmap_arg.offset;
+
+ igt_info("A: {fd:%d, handle:%d, offset:%"PRIx64"}\n",
+ A, a, offset_a);
+ igt_info("B: {fd:%d, handle:%d, offset:%"PRIx64"}\n",
+ B, b, offset_b);
+
+ close(B);
+
+ ptr = mmap64(0, 4096, PROT_READ, MAP_SHARED, A, offset_a);
+ igt_assert(ptr != MAP_FAILED);
+ munmap(ptr, 4096);
+
+ close(A);
+
+ ptr = mmap64(0, 4096, PROT_READ, MAP_SHARED, A, offset_a);
+ igt_assert(ptr == MAP_FAILED);
+}
+
+static void
test_write_gtt(int fd)
{
uint32_t dst;
@@ -945,6 +983,8 @@ igt_main
test_write_cpu_read_gtt(fd);
igt_subtest("basic-wc")
test_wc(fd);
+ igt_subtest("isolation")
+ test_isolation(fd);
igt_subtest("pf-nonblock")
test_pf_nonblock(fd);
diff --git a/tests/i915/gem_mocs_settings.c b/tests/i915/gem_mocs_settings.c
index 1a311b8c..3ad94149 100644
--- a/tests/i915/gem_mocs_settings.c
+++ b/tests/i915/gem_mocs_settings.c
@@ -63,6 +63,7 @@ static const char * const test_modes[] = {
#define GEN9_MFX1_MOCS_0 (0xcA00) /* Media 1 MOCS base register*/
#define GEN9_VEBOX_MOCS_0 (0xcB00) /* Video MOCS base register*/
#define GEN9_BLT_MOCS_0 (0xcc00) /* Blitter MOCS base register*/
+#define GEN12_GLOBAL_MOCS (0x4000)
#define ICELAKE_MOCS_PTE {0x00000004, 0x0030, 0x1}
#define MOCS_PTE {0x00000038, 0x0030, 0x1}
@@ -78,6 +79,40 @@ struct mocs_table {
};
/* The first entries in the MOCS tables are defined by uABI */
+
+static const struct mocs_entry tigerlake_mocs_table[GEN11_NUM_MOCS_ENTRIES] = {
+ [2] = { 0x00000037, 0x0030, 0x1},
+ [3] = { 0x00000005, 0x0010, 0x1},
+ [4] = { 0x00000005, 0x0030, 0x1},
+ [5] = { 0x00000037, 0x0010, 0x1},
+ [6] = { 0x00000017, 0x0010, 0x1},
+ [7] = { 0x00000017, 0x0030, 0x1},
+ [8] = { 0x00000027, 0x0010, 0x1},
+ [9] = { 0x00000027, 0x0030, 0x1},
+ [10] = { 0x00000077, 0x0010, 0x1},
+ [11] = { 0x00000077, 0x0030, 0x1},
+ [12] = { 0x00000057, 0x0010, 0x1},
+ [13] = { 0x00000057, 0x0030, 0x1},
+ [14] = { 0x00000067, 0x0010, 0x1},
+ [15] = { 0x00000067, 0x0030, 0x1},
+ [16] = { 0x00004005, 0x0010, 0x1},
+ [17] = { 0x00004005, 0x0030, 0x1},
+ [18] = { 0x00060037, 0x0030, 0x1},
+ [19] = { 0x00000737, 0x0030, 0x1},
+ [20] = { 0x00000337, 0x0030, 0x1},
+ [21] = { 0x00000137, 0x0030, 0x1},
+ [22] = { 0x000003b7, 0x0030, 0x1},
+ [23] = { 0x000007b7, 0x0030, 0x1},
+ [48] = { 0x00000037, 0x0030, 0x1},
+ [49] = { 0x00000005, 0x0030, 0x1},
+ [50] = { 0x00000037, 0x0010, 0x1},
+ [51] = { 0x00000005, 0x0010, 0x1},
+ [60] = { 0x00000037, 0x0010, 0x1},
+ [61] = { 0x00004005, 0x0030, 0x1},
+ [62] = { 0x00000037, 0x0010, 0x1},
+ [63] = { 0x00000037, 0x0010, 0x1},
+};
+
static const struct mocs_entry icelake_mocs_table[GEN11_NUM_MOCS_ENTRIES] = {
[0] = { 0x00000005, 0x0010, 0x1},
[1] = ICELAKE_MOCS_PTE,
@@ -101,7 +136,6 @@ static const struct mocs_entry icelake_mocs_table[GEN11_NUM_MOCS_ENTRIES] = {
[21] = { 0x00000137, 0x0030, 0x1},
[22] = { 0x000003b7, 0x0030, 0x1},
[23] = { 0x000007b7, 0x0030, 0x1},
- [24 ... 61] = ICELAKE_MOCS_PTE,
[62] = { 0x00000037, 0x0010, 0x1},
[63] = { 0x00000037, 0x0010, 0x1},
};
@@ -132,12 +166,17 @@ static const uint32_t write_values[GEN9_NUM_MOCS_ENTRIES] = {
[0 ... GEN9_NUM_MOCS_ENTRIES - 1] = 0xFFFFFFFF,
};
+static bool has_global_mocs(int fd)
+{
+ return intel_gen(intel_get_drm_devid(fd)) >= 12;
+}
+
static bool get_mocs_settings(int fd, struct mocs_table *table, bool dirty)
{
uint32_t devid = intel_get_drm_devid(fd);
bool result = false;
- if (IS_SKYLAKE(devid) || IS_KABYLAKE(devid)) {
+ if (IS_SKYLAKE(devid) || IS_KABYLAKE(devid) || IS_COMETLAKE(devid)) {
if (dirty) {
table->size = ARRAY_SIZE(dirty_skylake_mocs_table);
table->table = dirty_skylake_mocs_table;
@@ -159,6 +198,10 @@ static bool get_mocs_settings(int fd, struct mocs_table *table, bool dirty)
table->size = ARRAY_SIZE(icelake_mocs_table);
table->table = icelake_mocs_table;
result = true;
+ } else if (IS_TIGERLAKE(devid)) {
+ table->size = ARRAY_SIZE(tigerlake_mocs_table);
+ table->table = tigerlake_mocs_table;
+ result = true;
}
return result;
@@ -167,8 +210,11 @@ static bool get_mocs_settings(int fd, struct mocs_table *table, bool dirty)
#define LOCAL_I915_EXEC_BSD1 (I915_EXEC_BSD | (1<<13))
#define LOCAL_I915_EXEC_BSD2 (I915_EXEC_BSD | (2<<13))
-static uint32_t get_engine_base(uint32_t engine)
+static uint32_t get_engine_base(int fd, uint32_t engine)
{
+ if (has_global_mocs(fd))
+ return GEN12_GLOBAL_MOCS;
+
switch (engine) {
case LOCAL_I915_EXEC_BSD1: return GEN9_MFX0_MOCS_0;
case LOCAL_I915_EXEC_BSD2: return GEN9_MFX1_MOCS_0;
@@ -302,7 +348,7 @@ static void check_control_registers(int fd,
uint32_t ctx_id,
bool dirty)
{
- const uint32_t reg_base = get_engine_base(engine);
+ const uint32_t reg_base = get_engine_base(fd, engine);
uint32_t dst_handle = gem_create(fd, 4096);
uint32_t *read_regs;
struct mocs_table table;
@@ -320,10 +366,16 @@ static void check_control_registers(int fd,
gem_set_domain(fd, dst_handle, I915_GEM_DOMAIN_CPU, 0);
for (int index = 0; index < table.size; index++) {
+ uint32_t val, read_val;
+
if (!table.table[index].used)
continue;
- igt_assert_eq_u32(read_regs[index],
- table.table[index].control_value);
+
+ read_val = read_regs[index];
+ val = table.table[index].control_value;
+ igt_assert_f(read_val == val,
+ "engine=%u index=%u read_value=0x%08x value=0x%08x\n",
+ engine, index, read_val, val);
}
munmap(read_regs, 4096);
@@ -428,7 +480,7 @@ static void write_dirty_mocs(int fd,
else
num_of_mocs_entries = GEN9_NUM_MOCS_ENTRIES;
- write_registers(fd, ctx_id, get_engine_base(engine),
+ write_registers(fd, ctx_id, get_engine_base(fd, engine),
write_values, num_of_mocs_entries,
engine, privileged);
@@ -454,7 +506,7 @@ static void run_test(int fd, unsigned engine, unsigned flags, unsigned mode)
gem_require_ring(fd, engine);
/* Skip if we don't know where the registers are for this engine */
- igt_require(get_engine_base(engine));
+ igt_require(get_engine_base(fd, engine));
if (flags & MOCS_NON_DEFAULT_CTX)
ctx_id = gem_context_create(fd);
diff --git a/tests/i915/gem_persistent_relocs.c b/tests/i915/gem_persistent_relocs.c
index 452fe686..dff4e9a7 100644
--- a/tests/i915/gem_persistent_relocs.c
+++ b/tests/i915/gem_persistent_relocs.c
@@ -281,10 +281,13 @@ static void do_forked_test(int fd, unsigned flags)
struct igt_helper_process thrasher = {};
if (flags & (THRASH | THRASH_INACTIVE)) {
- uint64_t val = (flags & THRASH_INACTIVE) ?
- (DROP_RETIRE | DROP_BOUND | DROP_UNBOUND) : DROP_ALL;
-
igt_fork_helper(&thrasher) {
+ uint64_t val;
+
+ val = DROP_RETIRE | DROP_BOUND | DROP_UNBOUND;
+ if (!(flags & THRASH_INACTIVE))
+ val |= DROP_ACTIVE | DROP_SHRINK_ALL;
+
while (1) {
usleep(1000);
igt_drop_caches_set(fd, val);
diff --git a/tests/i915/gem_reloc_vs_gpu.c b/tests/i915/gem_reloc_vs_gpu.c
index d421e434..328730a9 100644
--- a/tests/i915/gem_reloc_vs_gpu.c
+++ b/tests/i915/gem_reloc_vs_gpu.c
@@ -258,10 +258,13 @@ static void do_forked_test(int fd, unsigned flags)
igt_require_hang_ring(fd, I915_EXEC_BLT);
if (flags & (THRASH | THRASH_INACTIVE)) {
- uint64_t val = (flags & THRASH_INACTIVE) ?
- (DROP_RETIRE | DROP_BOUND | DROP_UNBOUND) : DROP_ALL;
-
igt_fork_helper(&thrasher) {
+ uint64_t val;
+
+ val = DROP_RETIRE | DROP_BOUND | DROP_UNBOUND;
+ if (!(flags & THRASH_INACTIVE))
+ val |= DROP_ACTIVE | DROP_SHRINK_ALL;
+
while (1) {
usleep(1000);
igt_drop_caches_set(fd, val);
diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
index 037ff005..3db754f5 100644
--- a/tests/i915/gem_shrink.c
+++ b/tests/i915/gem_shrink.c
@@ -45,6 +45,13 @@ static void get_pages(int fd, uint64_t alloc)
gem_madvise(fd, handle, I915_MADV_DONTNEED);
}
+static void get_pages_dirty(int fd, uint64_t alloc)
+{
+ uint32_t handle = gem_create(fd, alloc);
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ gem_madvise(fd, handle, I915_MADV_DONTNEED);
+}
+
static void pwrite_(int fd, uint64_t alloc)
{
uint32_t tmp;
@@ -214,7 +221,8 @@ static void hang(int fd, uint64_t alloc)
munmap(obj, obj_size);
}
-static void userptr(int fd, uint64_t alloc)
+static void userptr(int fd, uint64_t alloc, unsigned int flags)
+#define UDIRTY (1 << 0)
{
struct local_i915_gem_userptr userptr;
void *ptr;
@@ -231,7 +239,11 @@ static void userptr(int fd, uint64_t alloc)
userptr.user_ptr = to_user_pointer(ptr);
do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
- gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
+ if (flags & UDIRTY)
+ gem_set_domain(fd, userptr.handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ else
+ gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
madvise(ptr, alloc, MADV_FREE);
}
@@ -273,7 +285,8 @@ static void leak(int fd, uint64_t alloc)
#define SOLO 1
#define USERPTR 2
-#define OOM 4
+#define USERPTR_DIRTY 4
+#define OOM 8
static void run_test(int nchildren, uint64_t alloc,
void (*func)(int, uint64_t), unsigned flags)
@@ -309,7 +322,20 @@ static void run_test(int nchildren, uint64_t alloc,
igt_until_timeout(timeout) {
int fd = drm_open_driver(DRIVER_INTEL);
for (int pass = 0; pass < nchildren; pass++)
- userptr(fd, alloc);
+ userptr(fd, alloc, 0);
+ close(fd);
+ }
+ }
+ nchildren = (nchildren + 1)/2;
+ }
+
+ if (flags & USERPTR_DIRTY) {
+ igt_require(has_userptr());
+ igt_fork(child, (nchildren + 1)/2) {
+ igt_until_timeout(timeout) {
+ int fd = drm_open_driver(DRIVER_INTEL);
+ for (int pass = 0; pass < nchildren; pass++)
+ userptr(fd, alloc, UDIRTY);
close(fd);
}
}
@@ -373,6 +399,7 @@ igt_main
void (*func)(int, uint64_t);
} tests[] = {
{ "get-pages", get_pages },
+ { "get-pages-dirty", get_pages_dirty },
{ "pwrite", pwrite_ },
{ "pread", pread_ },
{ "mmap-gtt", mmap_gtt },
@@ -390,6 +417,7 @@ igt_main
{ "-sanitycheck", SOLO },
{ "", 0 },
{ "-userptr", USERPTR },
+ { "-userptr-dirty", USERPTR | USERPTR_DIRTY },
{ "-oom", USERPTR | OOM },
{ NULL },
};
diff --git a/tests/i915/gem_userptr_blits.c b/tests/i915/gem_userptr_blits.c
index 1373f160..5f7770c9 100644
--- a/tests/i915/gem_userptr_blits.c
+++ b/tests/i915/gem_userptr_blits.c
@@ -1662,20 +1662,24 @@ struct stress_thread_data {
static void *mm_stress_thread(void *data)
{
struct stress_thread_data *stdata = (struct stress_thread_data *)data;
+ const size_t sz = 2 << 20;
void *ptr;
- int ret;
while (!stdata->stop) {
- ptr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ptr = mmap(NULL, sz, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED) {
stdata->exit_code = -EFAULT;
break;
}
- ret = munmap(ptr, PAGE_SIZE);
- if (ret) {
- stdata->exit_code = errno;
- break;
+
+ madvise(ptr, sz, MADV_HUGEPAGE);
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)ptr + page) = 0;
+
+ if (munmap(ptr, sz)) {
+ stdata->exit_code = errno;
+ break;
}
}
@@ -1713,6 +1717,35 @@ static void test_stress_mm(int fd)
igt_assert_eq(stdata.exit_code, 0);
}
+static void test_stress_purge(int fd)
+{
+ struct stress_thread_data stdata;
+ uint32_t handle;
+ pthread_t t;
+ void *ptr;
+
+ memset(&stdata, 0, sizeof(stdata));
+
+ igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+ igt_assert(!pthread_create(&t, NULL, mm_stress_thread, &stdata));
+
+ igt_until_timeout(150) {
+ gem_userptr(fd, ptr, PAGE_SIZE, 0, userptr_flags, &handle);
+
+ gem_set_domain(fd, handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ intel_purge_vm_caches(fd);
+
+ gem_close(fd, handle);
+ }
+
+ free(ptr);
+
+ stdata.stop = 1;
+ igt_assert(!pthread_join(t, NULL));
+ igt_assert_eq(stdata.exit_code, 0);
+}
+
struct userptr_close_thread_data {
int fd;
void *ptr;
@@ -1975,6 +2008,8 @@ igt_main_args("c:", NULL, help_str, opt_handler, NULL)
igt_subtest("stress-mm")
test_stress_mm(fd);
+ igt_subtest("stress-purge")
+ test_stress_purge(fd);
igt_subtest("stress-mm-invalidate-close")
test_invalidate_close_race(fd, false);
diff --git a/tests/i915/i915_pm_rpm.c b/tests/i915/i915_pm_rpm.c
index e2c7ba21..2168ff72 100644
--- a/tests/i915/i915_pm_rpm.c
+++ b/tests/i915/i915_pm_rpm.c
@@ -50,6 +50,7 @@
#include "igt_sysfs.h"
#include "igt_debugfs.h"
#include "igt_device.h"
+#include "igt_edid.h"
#define MSR_PKG_CST_CONFIG_CONTROL 0xE2
/* HSW/BDW: */
@@ -655,10 +656,10 @@ static bool i2c_read_edid(const char *connector_name, unsigned char *edid)
return rc >= 0;
}
-static void format_hex_string(const unsigned char edid[static EDID_LENGTH],
- char buf[static EDID_LENGTH * 5 + 1])
+static void format_hex_string(const unsigned char edid[static EDID_BLOCK_SIZE],
+ char buf[static EDID_BLOCK_SIZE * 5 + 1])
{
- for (int i = 0; i < EDID_LENGTH; ++i)
+ for (int i = 0; i < EDID_BLOCK_SIZE; ++i)
sprintf(buf+i*5, "0x%02x ", edid[i]);
}
@@ -670,7 +671,7 @@ static void test_i2c(struct mode_set_data *data)
for (int i = 0; i < data->res->count_connectors; i++) {
unsigned char *drm_edid = data->edids[i] ? data->edids[i]->data : NULL;
- unsigned char i2c_edid[EDID_LENGTH] = {};
+ unsigned char i2c_edid[EDID_BLOCK_SIZE] = {};
igt_output_t *output = igt_output_from_connector(&display,
data->connectors[i]);
@@ -694,13 +695,13 @@ static void test_i2c(struct mode_set_data *data)
continue;
if (got_i2c_edid && got_drm_edid)
- edids_equal = (0 == memcmp(drm_edid, i2c_edid, EDID_LENGTH));
+ edids_equal = (0 == memcmp(drm_edid, i2c_edid, EDID_BLOCK_SIZE));
else
edids_equal = false;
if (!edids_equal) {
- char buf[5 * EDID_LENGTH + 1];
+ char buf[5 * EDID_BLOCK_SIZE + 1];
igt_critical("Detected EDID mismatch on connector %s\n",
connector_name);
diff --git a/tests/i915/i915_pm_sseu.c b/tests/i915/i915_pm_sseu.c
index 252df7d3..0b936982 100644
--- a/tests/i915/i915_pm_sseu.c
+++ b/tests/i915/i915_pm_sseu.c
@@ -199,7 +199,7 @@ dbg_get_status(struct status *stat)
if (dbg_has_line(first, last, "Enabled Subslice Per Slice:")) {
stat->hw.subslice_per =
dbg_get_int(first, last, "Enabled Subslice Per Slice:");
- } else {
+ } else if (dbg_has_line(first, last, "Enabled Slice0 subslices:")) {
stat->hw.subslice_per =
dbg_get_int(first, last, "Enabled Slice0 subslices:");
}
diff --git a/tests/igt_command_line.sh b/tests/igt_command_line.sh
index 92643c4d..a019e3a5 100755
--- a/tests/igt_command_line.sh
+++ b/tests/igt_command_line.sh
@@ -90,7 +90,7 @@ check_test ()
# Subtest enumeration of kernel selftest launchers depends
# on the running kernel. If selftests are not enabled,
# they will output nothing and exit with 0.
- if [ "$testname" != "i915_selftest" -a "$testname" != "drm_mm" -a "$testname" != "kms_selftest" ]; then
+ if [ "$testname" != "i915_selftest" -a "$testname" != "drm_mm" -a "$testname" != "kms_selftest" -a "$testname" != "dmabuf" ]; then
fail $test
fi
fi
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index 29d09a65..e78e7fd0 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -78,7 +78,6 @@ igt@gem_mmap_gtt@basic-small-bo-tiledx
igt@gem_mmap_gtt@basic-small-bo-tiledy
igt@gem_mmap_gtt@basic-small-copy
igt@gem_mmap_gtt@basic-small-copy-xy
-igt@gem_mmap_gtt@basic-wc
igt@gem_mmap_gtt@basic-write
igt@gem_mmap_gtt@basic-write-cpu-read-gtt
igt@gem_mmap_gtt@basic-write-gtt
diff --git a/tests/kms_3d.c b/tests/kms_3d.c
index 8ade6d34..b970b3b5 100644
--- a/tests/kms_3d.c
+++ b/tests/kms_3d.c
@@ -31,7 +31,7 @@ igt_simple_main
int drm_fd;
drmModeRes *res;
drmModeConnector *connector;
- const unsigned char *edid;
+ const struct edid *edid;
int mode_count, connector_id;
drm_fd = drm_open_driver_master(DRIVER_INTEL);
@@ -46,8 +46,7 @@ igt_simple_main
connector = drmModeGetConnectorCurrent(drm_fd, res->connectors[i]);
- if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA &&
- connector->connection == DRM_MODE_DISCONNECTED)
+ if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
break;
drmModeFreeConnector(connector);
@@ -56,6 +55,8 @@ igt_simple_main
}
igt_require(connector);
+ kmstest_unset_all_crtcs(drm_fd, res);
+
edid = igt_kms_get_3d_edid();
kmstest_force_edid(drm_fd, connector, edid);
diff --git a/tests/kms_addfb_basic.c b/tests/kms_addfb_basic.c
index 20dfd4f2..666e7165 100644
--- a/tests/kms_addfb_basic.c
+++ b/tests/kms_addfb_basic.c
@@ -131,6 +131,7 @@ static void invalid_tests(int fd)
}
igt_subtest("clobberred-modifier") {
+ igt_require_intel(fd);
f.flags = 0;
f.modifier[0] = 0;
gem_set_tiling(fd, gem_bo, I915_TILING_X, 512*4);
@@ -302,6 +303,7 @@ static void tiling_tests(int fd)
igt_subtest_group {
igt_fixture {
+ igt_require_intel(fd);
tiled_x_bo = igt_create_bo_with_dimensions(fd, 1024, 1024,
DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_X_TILED,
1024*4, NULL, NULL, NULL);
@@ -447,6 +449,7 @@ static void size_tests(int fd)
}
igt_subtest("bo-too-small-due-to-tiling") {
+ igt_require_intel(fd);
gem_set_tiling(fd, gem_bo_small, I915_TILING_X, 1024*4);
igt_assert(drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &f) == -1 &&
errno == EINVAL);
@@ -498,6 +501,7 @@ static void addfb25_tests(int fd)
igt_subtest_group {
igt_fixture {
+ igt_require_intel(fd);
gem_set_tiling(fd, gem_bo, I915_TILING_X, 1024*4);
igt_require_fb_modifiers(fd);
}
diff --git a/tests/kms_available_modes_crc.c b/tests/kms_available_modes_crc.c
index 07772767..786d50e6 100644
--- a/tests/kms_available_modes_crc.c
+++ b/tests/kms_available_modes_crc.c
@@ -102,7 +102,6 @@ static void generate_comparison_crc_list(data_t *data, igt_output_t *output)
igt_plane_set_fb(primary, &data->primary_fb);
igt_display_commit2(&data->display, data->commit);
- igt_pipe_crc_drain(data->pipe_crc);
igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, &data->cursor_crc);
igt_plane_set_fb(primary, NULL);
igt_display_commit2(&data->display, data->commit);
@@ -114,7 +113,6 @@ static void generate_comparison_crc_list(data_t *data, igt_output_t *output)
igt_plane_set_fb(primary, &data->primary_fb);
igt_display_commit2(&data->display, data->commit);
- igt_pipe_crc_drain(data->pipe_crc);
igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, &data->fullscreen_crc);
igt_remove_fb(data->gfx_fd, &data->primary_fb);
@@ -313,7 +311,6 @@ test_one_mode(data_t* data, igt_output_t *output, igt_plane_t* plane,
igt_display_commit2(&data->display, data->commit);
igt_wait_for_vblank(data->gfx_fd, pipe);
- igt_pipe_crc_drain(data->pipe_crc);
igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, &current_crc);
if (plane->type != DRM_PLANE_TYPE_CURSOR) {
diff --git a/tests/kms_ccs.c b/tests/kms_ccs.c
index 2f08a837..1ce66cde 100644
--- a/tests/kms_ccs.c
+++ b/tests/kms_ccs.c
@@ -297,17 +297,13 @@ static int test_ccs(data_t *data)
return valid_tests;
}
-static int test_output(data_t *data)
+static int __test_output(data_t *data)
{
igt_display_t *display = &data->display;
int i, valid_tests = 0;
- igt_display_require_output_on_pipe(display, data->pipe);
-
- /* Sets data->output with a valid output. */
- for_each_valid_output_on_pipe(display, data->pipe, data->output) {
- break;
- }
+ data->output = igt_get_single_output_for_pipe(display, data->pipe);
+ igt_require(data->output);
igt_output_set_pipe(data->output, data->pipe);
@@ -322,6 +318,12 @@ static int test_output(data_t *data)
return valid_tests;
}
+static void test_output(data_t *data)
+{
+ int valid_tests = __test_output(data);
+ igt_require_f(valid_tests > 0, "CCS not supported, skipping\n");
+}
+
static data_t data;
igt_main
@@ -345,19 +347,19 @@ igt_main
data.flags = TEST_BAD_PIXEL_FORMAT;
igt_subtest_f("pipe-%s-bad-pixel-format", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_BAD_ROTATION_90;
igt_subtest_f("pipe-%s-bad-rotation-90", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_CRC;
igt_subtest_f("pipe-%s-crc-primary-basic", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_CRC | TEST_ROTATE_180;
igt_subtest_f("pipe-%s-crc-primary-rotation-180", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_CRC;
igt_subtest_f("pipe-%s-crc-sprite-planes-basic", pipe_name) {
@@ -368,25 +370,26 @@ igt_main
for_each_plane_on_pipe(&data.display, data.pipe, data.plane) {
if (data.plane->type == DRM_PLANE_TYPE_PRIMARY)
continue;
- valid_tests += test_output(&data);
+ valid_tests += __test_output(&data);
}
- igt_require(valid_tests);
+ igt_require_f(valid_tests > 0,
+ "CCS not supported, skipping\n");
}
data.plane = NULL;
data.flags = TEST_NO_AUX_BUFFER;
igt_subtest_f("pipe-%s-missing-ccs-buffer", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_BAD_CCS_HANDLE;
igt_subtest_f("pipe-%s-ccs-on-another-bo", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
data.flags = TEST_BAD_AUX_STRIDE;
igt_subtest_f("pipe-%s-bad-aux-stride", pipe_name)
- igt_require(test_output(&data));
+ test_output(&data);
}
igt_fixture
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index b7d30a2d..d6aec8b9 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -29,6 +29,7 @@
#include "igt_vc4.h"
#include "igt_edid.h"
#include "igt_eld.h"
+#include "igt_infoframe.h"
#include <fcntl.h>
#include <pthread.h>
@@ -40,8 +41,9 @@ enum test_edid {
TEST_EDID_ALT,
TEST_EDID_HDMI_AUDIO,
TEST_EDID_DP_AUDIO,
+ TEST_EDID_ASPECT_RATIO,
};
-#define TEST_EDID_COUNT 4
+#define TEST_EDID_COUNT 5
typedef struct {
struct chamelium *chamelium;
@@ -55,6 +57,7 @@ typedef struct {
} data_t;
#define HOTPLUG_TIMEOUT 20 /* seconds */
+#define ONLINE_TIMEOUT 20 /* seconds */
#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
@@ -118,15 +121,25 @@ reprobe_connector(data_t *data, struct chamelium_port *port)
return status;
}
+static const char *connection_str(drmModeConnection c)
+{
+ switch (c) {
+ case DRM_MODE_CONNECTED:
+ return "connected";
+ case DRM_MODE_DISCONNECTED:
+ return "disconnected";
+ case DRM_MODE_UNKNOWNCONNECTION:
+ return "unknown";
+ }
+ assert(0); /* unreachable */
+}
+
static void
wait_for_connector(data_t *data, struct chamelium_port *port,
drmModeConnection status)
{
- bool finished = false;
-
- igt_debug("Waiting for %s to %sconnect...\n",
- chamelium_port_get_name(port),
- status == DRM_MODE_DISCONNECTED ? "dis" : "");
+ igt_debug("Waiting for %s to get %s...\n",
+ chamelium_port_get_name(port), connection_str(status));
/*
* Rely on simple reprobing so we don't fail tests that don't require
@@ -134,14 +147,14 @@ wait_for_connector(data_t *data, struct chamelium_port *port,
*/
igt_until_timeout(HOTPLUG_TIMEOUT) {
if (reprobe_connector(data, port) == status) {
- finished = true;
return;
}
usleep(50000);
}
- igt_assert(finished);
+ igt_assert_f(false, "Timed out waiting for %s to get %s\n",
+ chamelium_port_get_name(port), connection_str(status));
}
static int chamelium_vga_modes[][2] = {
@@ -234,6 +247,7 @@ test_basic_hotplug(data_t *data, struct chamelium_port *port, int toggle_count)
{
struct udev_monitor *mon = igt_watch_hotplug();
int i;
+ drmModeConnection status;
reset_state(data, NULL);
igt_hpd_storm_set_threshold(data->drm_fd, 0);
@@ -243,24 +257,31 @@ test_basic_hotplug(data_t *data, struct chamelium_port *port, int toggle_count)
/* Check if we get a sysfs hotplug event */
chamelium_plug(data->chamelium, port);
- igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
- igt_assert_eq(reprobe_connector(data, port),
- DRM_MODE_CONNECTED);
+ igt_assert_f(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT),
+ "Timed out waiting for hotplug uevent\n");
+ status = reprobe_connector(data, port);
+ igt_assert_f(status == DRM_MODE_CONNECTED,
+ "Invalid connector status after hotplug: "
+ "got %s, expected connected\n",
+ connection_str(status));
igt_flush_hotplugs(mon);
/* Now check if we get a hotplug from disconnection */
chamelium_unplug(data->chamelium, port);
- igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
- igt_assert_eq(reprobe_connector(data, port),
- DRM_MODE_DISCONNECTED);
+ igt_assert_f(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT),
+ "Timed out waiting for unplug uevent\n");
+ igt_assert_f(status == DRM_MODE_DISCONNECTED,
+ "Invalid connector status after hotplug: "
+ "got %s, expected disconnected\n",
+ connection_str(status));
}
igt_cleanup_hotplug(mon);
igt_hpd_storm_reset(data->drm_fd);
}
-static const unsigned char *get_edid(enum test_edid edid);
+static const struct edid *get_edid(enum test_edid edid);
static void set_edid(data_t *data, struct chamelium_port *port,
enum test_edid edid)
@@ -289,6 +310,7 @@ test_edid_read(data_t *data, struct chamelium_port *port, enum test_edid edid)
igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
&edid_blob_id, NULL));
+ igt_assert(edid_blob_id != 0);
igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
edid_blob_id));
@@ -348,6 +370,7 @@ try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
igt_system_suspend_autoresume(state, test);
igt_assert(wait_for_hotplug(mon, &timeout));
+ chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
if (port) {
igt_assert_eq(reprobe_connector(data, port), target_state);
@@ -453,8 +476,8 @@ test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
igt_flush_hotplugs(mon);
igt_system_suspend_autoresume(state, test);
-
igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
+ chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
get_connectors_link_status_failed(data, link_status_failed[1]);
@@ -539,6 +562,145 @@ enable_output(data_t *data,
drmModeFreeConnector(connector);
}
+static bool find_mode(const drmModeModeInfo *list, size_t list_len,
+ const drmModeModeInfo *mode)
+{
+ size_t i;
+
+ for (i = 0; i < list_len; i++) {
+ if (memcmp(&list[i], mode, sizeof(*mode)) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void check_modes_subset(const drmModeModeInfo *prev, size_t prev_len,
+ const drmModeModeInfo *cur, size_t cur_len)
+{
+ size_t i;
+
+ for (i = 0; i < cur_len; i++) {
+ igt_assert_f(find_mode(prev, prev_len, &cur[i]),
+ "Got new mode %s after link status failure\n",
+ cur[i].name);
+ }
+
+ igt_assert(cur_len <= prev_len); /* safety net */
+ igt_debug("New mode list contains %zu less modes\n",
+ prev_len - cur_len);
+}
+
+static bool are_fallback_modes(const drmModeModeInfo *modes, size_t modes_len)
+{
+ igt_assert(modes_len > 0);
+
+ return modes[0].hdisplay <= 1024 && modes[0].vdisplay <= 768;
+}
+
+static void
+test_link_status(data_t *data, struct chamelium_port *port)
+{
+ drmModeConnector *connector;
+ igt_output_t *output;
+ igt_plane_t *primary;
+ drmModeModeInfo *prev_modes;
+ size_t prev_modes_len;
+ drmModeModeInfo mode = {0};
+ uint32_t link_status_id;
+ uint64_t link_status;
+ bool has_prop;
+ unsigned int fb_id = 0;
+ struct igt_fb fb;
+ struct udev_monitor *mon;
+
+ igt_require(chamelium_supports_trigger_link_failure(data->chamelium));
+
+ reset_state(data, port);
+
+ output = prepare_output(data, port, TEST_EDID_BASE);
+ connector = chamelium_port_get_connector(data->chamelium, port, false);
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_assert(primary);
+
+ has_prop = kmstest_get_property(data->drm_fd, connector->connector_id,
+ DRM_MODE_OBJECT_CONNECTOR,
+ "link-status", &link_status_id,
+ &link_status, NULL);
+ igt_require(has_prop);
+ igt_assert_f(link_status == DRM_MODE_LINK_STATUS_GOOD,
+ "Expected link status to be %d initially, got %"PRIu64"\n",
+ DRM_MODE_LINK_STATUS_GOOD, link_status);
+
+ igt_debug("Connector has %d modes\n", connector->count_modes);
+ prev_modes_len = connector->count_modes;
+ prev_modes = malloc(prev_modes_len * sizeof(drmModeModeInfo));
+ memcpy(prev_modes, connector->modes,
+ prev_modes_len * sizeof(drmModeModeInfo));
+
+ mon = igt_watch_hotplug();
+
+ while (1) {
+ if (link_status == DRM_MODE_LINK_STATUS_BAD) {
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_LINK_STATUS,
+ DRM_MODE_LINK_STATUS_GOOD);
+ }
+
+ if (memcmp(&connector->modes[0], &mode, sizeof(mode)) != 0) {
+ igt_assert(connector->count_modes > 0);
+ mode = connector->modes[0];
+ igt_debug("Modesetting with %s\n", mode.name);
+ if (fb_id > 0)
+ igt_remove_fb(data->drm_fd, &fb);
+ fb_id = igt_create_color_pattern_fb(data->drm_fd,
+ mode.hdisplay,
+ mode.vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ 0, 0, 0, &fb);
+ igt_assert(fb_id > 0);
+ enable_output(data, port, output, &mode, &fb);
+ } else {
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+ }
+
+ igt_debug("Triggering link failure\n");
+ chamelium_trigger_link_failure(data->chamelium, port);
+
+ igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
+ igt_assert_eq(reprobe_connector(data, port),
+ DRM_MODE_CONNECTED);
+
+ igt_flush_hotplugs(mon);
+
+ drmModeFreeConnector(connector);
+ connector = chamelium_port_get_connector(data->chamelium, port,
+ false);
+ link_status = igt_output_get_prop(output, IGT_CONNECTOR_LINK_STATUS);
+ igt_assert_f(link_status == DRM_MODE_LINK_STATUS_BAD,
+ "Expected link status to be %d after link failure, "
+ "got %"PRIu64"\n",
+ DRM_MODE_LINK_STATUS_BAD, link_status);
+ check_modes_subset(prev_modes, prev_modes_len,
+ connector->modes, connector->count_modes);
+ prev_modes_len = connector->count_modes;
+ memcpy(prev_modes, connector->modes,
+ connector->count_modes * sizeof(drmModeModeInfo));
+
+ if (are_fallback_modes(connector->modes, connector->count_modes)) {
+ igt_debug("Reached fallback modes\n");
+ break;
+ }
+ }
+
+ igt_cleanup_hotplug(mon);
+ igt_remove_fb(data->drm_fd, &fb);
+ free(prev_modes);
+ drmModeFreeConnector(connector);
+}
+
static void chamelium_paint_xr24_pattern(uint32_t *data,
size_t width, size_t height,
size_t stride, size_t block_size)
@@ -861,6 +1023,169 @@ static void test_mode_timings(data_t *data, struct chamelium_port *port)
drmModeFreeConnector(connector);
}
+/* Set of Video Identification Codes advertised in the EDID */
+static const uint8_t edid_ar_svds[] = {
+ 16, /* 1080p @ 60Hz, 16:9 */
+};
+
+struct vic_mode {
+ int hactive, vactive;
+ int vrefresh; /* Hz */
+ uint32_t picture_ar;
+};
+
+/* Maps Video Identification Codes to a mode */
+static const struct vic_mode vic_modes[] = {
+ [16] = {
+ .hactive = 1920,
+ .vactive = 1080,
+ .vrefresh = 60,
+ .picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
+ },
+};
+
+/* Maps aspect ratios to their mode flag */
+static const uint32_t mode_ar_flags[] = {
+ [DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
+};
+
+static enum infoframe_avi_picture_aspect_ratio
+get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
+{
+ /* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
+ switch (aspect_ratio) {
+ case DRM_MODE_PICTURE_ASPECT_4_3:
+ return INFOFRAME_AVI_PIC_AR_4_3;
+ case DRM_MODE_PICTURE_ASPECT_16_9:
+ return INFOFRAME_AVI_PIC_AR_16_9;
+ default:
+ return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
+ }
+}
+
+static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
+ drmModeModeInfo *drm_mode)
+{
+ uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
+
+ return vic_mode->hactive == drm_mode->hdisplay &&
+ vic_mode->vactive == drm_mode->vdisplay &&
+ vic_mode->vrefresh == drm_mode->vrefresh &&
+ ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
+}
+
+static const struct edid *get_aspect_ratio_edid(void)
+{
+ static unsigned char raw_edid[2 * EDID_BLOCK_SIZE] = {0};
+ struct edid *edid;
+ struct edid_ext *edid_ext;
+ struct edid_cea *edid_cea;
+ char *cea_data;
+ struct edid_cea_data_block *block;
+ size_t cea_data_size = 0, vsdb_size;
+ const struct cea_vsdb *vsdb;
+
+ edid = (struct edid *) raw_edid;
+ memcpy(edid, igt_kms_get_base_edid(), sizeof(struct edid));
+ edid->extensions_len = 1;
+ edid_ext = &edid->extensions[0];
+ edid_cea = &edid_ext->data.cea;
+ cea_data = edid_cea->data;
+
+ /* The HDMI VSDB advertises support for InfoFrames */
+ block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
+ vsdb = cea_vsdb_get_hdmi_default(&vsdb_size);
+ cea_data_size += edid_cea_data_block_set_vsdb(block, vsdb,
+ vsdb_size);
+
+ /* Short Video Descriptor */
+ block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
+ cea_data_size += edid_cea_data_block_set_svd(block, edid_ar_svds,
+ sizeof(edid_ar_svds));
+
+ assert(cea_data_size <= sizeof(edid_cea->data));
+
+ edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
+
+ edid_update_checksum(edid);
+
+ return edid;
+}
+
+static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
+{
+ igt_output_t *output;
+ igt_plane_t *primary;
+ drmModeConnector *connector;
+ drmModeModeInfo *mode;
+ int fb_id, i;
+ struct igt_fb fb;
+ bool found, ok;
+ struct chamelium_infoframe *infoframe;
+ struct infoframe_avi infoframe_avi;
+ uint8_t vic = 16; /* TODO: test more VICs */
+ const struct vic_mode *vic_mode;
+ uint32_t aspect_ratio;
+ enum infoframe_avi_picture_aspect_ratio frame_ar;
+
+ igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
+
+ reset_state(data, port);
+
+ output = prepare_output(data, port, TEST_EDID_ASPECT_RATIO);
+ connector = chamelium_port_get_connector(data->chamelium, port, false);
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_assert(primary);
+
+ vic_mode = &vic_modes[vic];
+ aspect_ratio = vic_mode->picture_ar;
+
+ found = false;
+ igt_assert(connector->count_modes > 0);
+ for (i = 0; i < connector->count_modes; i++) {
+ mode = &connector->modes[i];
+
+ if (vic_mode_matches_drm(vic_mode, mode)) {
+ found = true;
+ break;
+ }
+ }
+ igt_assert_f(found,
+ "Failed to find mode with the correct aspect ratio\n");
+
+ fb_id = igt_create_color_pattern_fb(data->drm_fd,
+ mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ 0, 0, 0, &fb);
+ igt_assert(fb_id > 0);
+
+ enable_output(data, port, output, mode, &fb);
+
+ infoframe = chamelium_get_last_infoframe(data->chamelium, port,
+ CHAMELIUM_INFOFRAME_AVI);
+ igt_assert_f(infoframe, "AVI InfoFrame not received\n");
+
+ ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
+ infoframe->payload, infoframe->payload_size);
+ igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
+
+ frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
+
+ igt_debug("Checking AVI InfoFrame\n");
+ igt_debug("Picture aspect ratio: got %d, expected %d\n",
+ infoframe_avi.picture_aspect_ratio, frame_ar);
+ igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
+ infoframe_avi.vic, vic);
+
+ igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
+ igt_assert(infoframe_avi.vic == vic);
+
+ chamelium_infoframe_destroy(infoframe);
+ igt_remove_fb(data->drm_fd, &fb);
+ drmModeFreeConnector(connector);
+}
+
/* Playback parameters control the audio signal we synthesize and send */
#define PLAYBACK_CHANNELS 2
@@ -1121,6 +1446,59 @@ static void audio_state_stop(struct audio_state *state, bool success)
success ? "ALL GREEN" : "FAILED");
}
+static void check_audio_infoframe(struct audio_state *state)
+{
+ struct chamelium_infoframe *infoframe;
+ struct infoframe_audio infoframe_audio;
+ struct infoframe_audio expected = {0};
+ bool ok;
+
+ if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
+ igt_debug("Skipping audio InfoFrame check: "
+ "Chamelium board doesn't support GetLastInfoFrame\n");
+ return;
+ }
+
+ expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
+ expected.channel_count = state->playback.channels;
+ expected.sampling_freq = state->playback.rate;
+ expected.sample_size = snd_pcm_format_width(state->playback.format);
+
+ infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
+ CHAMELIUM_INFOFRAME_AUDIO);
+ if (infoframe == NULL && state->playback.channels <= 2) {
+ /* Audio InfoFrames are optional for mono and stereo audio */
+ igt_debug("Skipping audio InfoFrame check: "
+ "no InfoFrame received\n");
+ return;
+ }
+ igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
+
+ ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
+ infoframe->payload, infoframe->payload_size);
+ chamelium_infoframe_destroy(infoframe);
+ igt_assert_f(ok, "failed to parse audio InfoFrame\n");
+
+ igt_debug("Checking audio InfoFrame:\n");
+ igt_debug("coding_type: got %d, expected %d\n",
+ infoframe_audio.coding_type, expected.coding_type);
+ igt_debug("channel_count: got %d, expected %d\n",
+ infoframe_audio.channel_count, expected.channel_count);
+ igt_debug("sampling_freq: got %d, expected %d\n",
+ infoframe_audio.sampling_freq, expected.sampling_freq);
+ igt_debug("sample_size: got %d, expected %d\n",
+ infoframe_audio.sample_size, expected.sample_size);
+
+ if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
+ igt_assert(infoframe_audio.coding_type == expected.coding_type);
+ if (infoframe_audio.channel_count >= 0)
+ igt_assert(infoframe_audio.channel_count == expected.channel_count);
+ if (infoframe_audio.sampling_freq >= 0)
+ igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
+ if (infoframe_audio.sample_size >= 0)
+ igt_assert(infoframe_audio.sample_size == expected.sample_size);
+}
+
static int
audio_output_frequencies_callback(void *data, void *buffer, int samples)
{
@@ -1246,6 +1624,8 @@ static bool test_audio_frequencies(struct audio_state *state)
free(channel);
audio_signal_fini(state->signal);
+ check_audio_infoframe(state);
+
return success;
}
@@ -2141,7 +2521,7 @@ test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
igt_hpd_storm_reset(data->drm_fd);
}
-static const unsigned char *get_edid(enum test_edid edid)
+static const struct edid *get_edid(enum test_edid edid)
{
switch (edid) {
case TEST_EDID_BASE:
@@ -2152,6 +2532,8 @@ static const unsigned char *get_edid(enum test_edid edid)
return igt_kms_get_hdmi_audio_edid();
case TEST_EDID_DP_AUDIO:
return igt_kms_get_dp_audio_edid();
+ case TEST_EDID_ASPECT_RATIO:
+ return get_aspect_ratio_edid();
}
assert(0); /* unreachable */
}
@@ -2234,6 +2616,9 @@ igt_main
test_hpd_storm_disable(&data, port,
HPD_STORM_PULSE_INTERVAL_DP);
+ connector_subtest("dp-link-status", DisplayPort)
+ test_link_status(&data, port);
+
connector_subtest("dp-edid-change-during-suspend", DisplayPort)
test_suspend_resume_edid_change(&data, port,
SUSPEND_STATE_MEM,
@@ -2431,6 +2816,9 @@ igt_main
connector_subtest("hdmi-audio-edid", HDMIA)
test_display_audio_edid(&data, port,
TEST_EDID_HDMI_AUDIO);
+
+ connector_subtest("hdmi-aspect-ratio", HDMIA)
+ test_display_aspect_ratio(&data, port);
}
igt_subtest_group {
diff --git a/tests/kms_content_protection.c b/tests/kms_content_protection.c
index ae6ab497..e676b60b 100644
--- a/tests/kms_content_protection.c
+++ b/tests/kms_content_protection.c
@@ -24,9 +24,13 @@
#include <poll.h>
#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <libudev.h>
#include "igt.h"
#include "igt_sysfs.h"
#include "igt_kms.h"
+#include "igt_kmod.h"
IGT_TEST_DESCRIPTION("Test content protection (HDCP)");
@@ -34,18 +38,39 @@ struct data {
int drm_fd;
igt_display_t display;
struct igt_fb red, green;
+ unsigned int cp_tests;
} data;
+/* Test flags */
+#define CP_DPMS (1 << 0)
+#define CP_LIC (1 << 1)
+#define CP_MEI_RELOAD (1 << 2)
+#define CP_TYPE_CHANGE (1 << 3)
+#define CP_UEVENT (1 << 4)
+
#define CP_UNDESIRED 0
#define CP_DESIRED 1
#define CP_ENABLED 2
+/*
+ * HDCP_CONTENT_TYPE_0 can be handled on both HDCP1.4 and HDCP2.2. Where as
+ * HDCP_CONTENT_TYPE_1 can be handled only through HDCP2.2.
+ */
+#define HDCP_CONTENT_TYPE_0 0
+#define HDCP_CONTENT_TYPE_1 1
+
#define LIC_PERIOD_MSEC (4 * 1000)
/* Kernel retry count=3, Max time per authentication allowed = 6Sec */
#define KERNEL_AUTH_TIME_ALLOWED_MSEC (3 * 6 * 1000)
#define KERNEL_DISABLE_TIME_ALLOWED_MSEC (1 * 1000)
#define FLIP_EVENT_POLLING_TIMEOUT_MSEC 1000
+__u8 facsimile_srm[] = {
+ 0x80, 0x0, 0x0, 0x05, 0x01, 0x0, 0x0, 0x36, 0x02, 0x51, 0x1E, 0xF2,
+ 0x1A, 0xCD, 0xE7, 0x26, 0x97, 0xF4, 0x01, 0x97, 0x10, 0x19, 0x92, 0x53,
+ 0xE9, 0xF0, 0x59, 0x95, 0xA3, 0x7A, 0x3B, 0xFE, 0xE0, 0x9C, 0x76, 0xDD,
+ 0x83, 0xAA, 0xC2, 0x5B, 0x24, 0xB3, 0x36, 0x84, 0x94, 0x75, 0x34, 0xDB,
+ 0x10, 0x9E, 0x3B, 0x23, 0x13, 0xD8, 0x7A, 0xC2, 0x30, 0x79, 0x84};
static void flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
unsigned int tv_usec, void *_data)
@@ -87,6 +112,137 @@ static int wait_flip_event(void)
return rc;
}
+static bool hdcp_event(struct udev_monitor *uevent_monitor,
+ struct udev *udev, uint32_t conn_id, uint32_t prop_id)
+{
+ struct udev_device *dev;
+ dev_t udev_devnum;
+ struct stat s;
+ const char *hotplug, *connector, *property;
+ bool ret = false;
+
+ dev = udev_monitor_receive_device(uevent_monitor);
+ if (!dev)
+ goto out;
+
+ udev_devnum = udev_device_get_devnum(dev);
+ fstat(data.display.drm_fd, &s);
+
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+ if (!(memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1)) {
+ igt_debug("Not a Hotplug event\n");
+ goto out_dev;
+ }
+
+ connector = udev_device_get_property_value(dev, "CONNECTOR");
+ if (!(memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ connector && atoi(connector) == conn_id)) {
+ igt_debug("Not for connector id: %u\n", conn_id);
+ goto out_dev;
+ }
+
+ property = udev_device_get_property_value(dev, "PROPERTY");
+ if (!(memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ property && atoi(property) == prop_id)) {
+ igt_debug("Not for property id: %u\n", prop_id);
+ goto out_dev;
+ }
+ ret = true;
+
+out_dev:
+ udev_device_unref(dev);
+out:
+ return ret;
+}
+
+static void hdcp_udev_fini(struct udev_monitor *uevent_monitor,
+ struct udev *udev)
+{
+ if (uevent_monitor)
+ udev_monitor_unref(uevent_monitor);
+ if (udev)
+ udev_unref(udev);
+}
+
+static int hdcp_udev_init(struct udev_monitor *uevent_monitor,
+ struct udev *udev)
+{
+ int ret = -EINVAL;
+
+ udev = udev_new();
+ if (!udev) {
+ igt_info("failed to create udev object\n");
+ goto out;
+ }
+
+ uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!uevent_monitor) {
+ igt_info("failed to create udev event monitor\n");
+ goto out;
+ }
+
+ ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
+ "drm",
+ "drm_minor");
+ if (ret < 0) {
+ igt_info("failed to filter for drm events\n");
+ goto out;
+ }
+
+ ret = udev_monitor_enable_receiving(uevent_monitor);
+ if (ret < 0) {
+ igt_info("failed to enable udev event reception\n");
+ goto out;
+ }
+
+ return udev_monitor_get_fd(uevent_monitor);
+
+out:
+ hdcp_udev_fini(uevent_monitor, udev);
+ return ret;
+}
+
+#define MAX_EVENTS 10
+static bool wait_for_hdcp_event(uint32_t conn_id, uint32_t prop_id,
+ uint32_t timeout_mSec)
+{
+
+ struct udev_monitor *uevent_monitor = NULL;
+ struct udev *udev = NULL;
+ int udev_fd, epoll_fd;
+ struct epoll_event event, events[MAX_EVENTS];
+ bool ret = false;
+
+ udev_fd = hdcp_udev_init(uevent_monitor, udev);
+ if (udev_fd < 0)
+ return false;
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ igt_info("Failed to create epoll fd. %d\n", epoll_fd);
+ goto out_ep_create;
+ }
+
+ event.events = EPOLLIN | EPOLLERR;
+ event.data.fd = 0;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, udev_fd, &event)) {
+ igt_info("failed to fd into epoll\n");
+ goto out_ep_ctl;
+ }
+
+ if (epoll_wait(epoll_fd, events, MAX_EVENTS, timeout_mSec))
+ ret = hdcp_event(uevent_monitor, udev, conn_id, prop_id);
+
+out_ep_ctl:
+ if (close(epoll_fd))
+ igt_info("failed to close the epoll fd\n");
+out_ep_create:
+ hdcp_udev_fini(uevent_monitor, udev);
+ return ret;
+}
+
static bool
wait_for_prop_value(igt_output_t *output, uint64_t expected,
uint32_t timeout_mSec)
@@ -94,13 +250,25 @@ wait_for_prop_value(igt_output_t *output, uint64_t expected,
uint64_t val;
int i;
- for (i = 0; i < timeout_mSec; i++) {
+ if (data.cp_tests & CP_UEVENT && expected != CP_UNDESIRED) {
+ igt_assert_f(wait_for_hdcp_event(output->id,
+ output->props[IGT_CONNECTOR_CONTENT_PROTECTION],
+ timeout_mSec), "uevent is not received");
+
val = igt_output_get_prop(output,
IGT_CONNECTOR_CONTENT_PROTECTION);
if (val == expected)
return true;
- usleep(1000);
+ } else {
+ for (i = 0; i < timeout_mSec; i++) {
+ val = igt_output_get_prop(output,
+ IGT_CONNECTOR_CONTENT_PROTECTION);
+ if (val == expected)
+ return true;
+ usleep(1000);
+ }
}
+
igt_info("prop_value mismatch %" PRId64 " != %" PRId64 "\n",
val, expected);
@@ -155,7 +323,8 @@ static void modeset_with_fb(const enum pipe pipe, igt_output_t *output,
commit_display_and_wait_for_flip(s);
}
-static bool test_cp_enable(igt_output_t *output, enum igt_commit_style s)
+static bool test_cp_enable(igt_output_t *output, enum igt_commit_style s,
+ int content_type, bool type_change)
{
igt_display_t *display = &data.display;
igt_plane_t *primary;
@@ -163,8 +332,15 @@ static bool test_cp_enable(igt_output_t *output, enum igt_commit_style s)
primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
- igt_output_set_prop_value(output,
- IGT_CONNECTOR_CONTENT_PROTECTION, CP_DESIRED);
+ if (!type_change)
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_CONTENT_PROTECTION,
+ CP_DESIRED);
+
+ if (output->props[IGT_CONNECTOR_HDCP_CONTENT_TYPE])
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_HDCP_CONTENT_TYPE,
+ content_type);
igt_display_commit2(display, s);
ret = wait_for_prop_value(output, CP_ENABLED,
@@ -201,13 +377,18 @@ static void test_cp_disable(igt_output_t *output, enum igt_commit_style s)
}
static void test_cp_enable_with_retry(igt_output_t *output,
- enum igt_commit_style s, int retry)
+ enum igt_commit_style s, int retry,
+ int content_type, bool expect_failure,
+ bool type_change)
{
+ int retry_orig = retry;
bool ret;
do {
- test_cp_disable(output, s);
- ret = test_cp_enable(output, s);
+ if (!type_change || retry_orig != retry)
+ test_cp_disable(output, s);
+
+ ret = test_cp_enable(output, s, content_type, type_change);
if (!ret && --retry)
igt_debug("Retry (%d/2) ...\n", 3 - retry);
@@ -216,7 +397,12 @@ static void test_cp_enable_with_retry(igt_output_t *output,
if (!ret)
test_cp_disable(output, s);
- igt_assert_f(ret, "Content Protection not enabled\n");
+ if (expect_failure)
+ igt_assert_f(!ret,
+ "CP Enabled. Though it is expected to fail\n");
+ else
+ igt_assert_f(ret, "Content Protection not enabled\n");
+
}
static bool igt_pipe_is_free(igt_display_t *display, enum pipe pipe)
@@ -239,9 +425,30 @@ static void test_cp_lic(igt_output_t *output)
igt_assert_f(!ret, "Content Protection LIC Failed\n");
}
+static bool write_srm_as_fw(const __u8 *srm, int len)
+{
+ int fd, ret, total = 0;
+
+ fd = open("/lib/firmware/display_hdcp_srm.bin",
+ O_WRONLY | O_CREAT, S_IRWXU);
+ do {
+ ret = write(fd, srm + total, len - total);
+ if (ret < 0)
+ ret = -errno;
+ if (ret == -EINTR || ret == -EAGAIN)
+ continue;
+ if (ret <= 0)
+ break;
+ total += ret;
+ } while (total != len);
+ close(fd);
+
+ return total < len ? false : true;
+}
+
static void test_content_protection_on_output(igt_output_t *output,
enum igt_commit_style s,
- bool dpms_test)
+ int content_type)
{
igt_display_t *display = &data.display;
igt_plane_t *primary;
@@ -262,10 +469,40 @@ static void test_content_protection_on_output(igt_output_t *output,
continue;
modeset_with_fb(pipe, output, s);
- test_cp_enable_with_retry(output, s, 3);
- test_cp_lic(output);
+ test_cp_enable_with_retry(output, s, 3, content_type, false,
+ false);
+
+ if (data.cp_tests & CP_TYPE_CHANGE) {
+ /* Type 1 -> Type 0 */
+ test_cp_enable_with_retry(output, s, 3,
+ HDCP_CONTENT_TYPE_0, false,
+ true);
+ /* Type 0 -> Type 1 */
+ test_cp_enable_with_retry(output, s, 3,
+ content_type, false,
+ true);
+ }
+
+ if (data.cp_tests & CP_MEI_RELOAD) {
+ igt_assert_f(!igt_kmod_unload("mei_hdcp", 0),
+ "mei_hdcp unload failed");
- if (dpms_test) {
+ /* Expected to fail */
+ test_cp_enable_with_retry(output, s, 3,
+ content_type, true, false);
+
+ igt_assert_f(!igt_kmod_load("mei_hdcp", NULL),
+ "mei_hdcp load failed");
+
+ /* Expected to pass */
+ test_cp_enable_with_retry(output, s, 3,
+ content_type, false, false);
+ }
+
+ if (data.cp_tests & CP_LIC)
+ test_cp_lic(output);
+
+ if (data.cp_tests & CP_DPMS) {
igt_pipe_set_prop_value(display, pipe,
IGT_CRTC_ACTIVE, 0);
igt_display_commit2(display, s);
@@ -277,7 +514,9 @@ static void test_content_protection_on_output(igt_output_t *output,
ret = wait_for_prop_value(output, CP_ENABLED,
KERNEL_AUTH_TIME_ALLOWED_MSEC);
if (!ret)
- test_cp_enable_with_retry(output, s, 2);
+ test_cp_enable_with_retry(output, s, 2,
+ content_type, false,
+ false);
}
test_cp_disable(output, s);
@@ -304,7 +543,8 @@ static void __debugfs_read(int fd, const char *param, char *buf, int len)
#define debugfs_read(fd, p, arr) __debugfs_read(fd, p, arr, sizeof(arr))
-#define MAX_SINK_HDCP_CAP_BUF_LEN 500
+#define MAX_SINK_HDCP_CAP_BUF_LEN 5000
+
static bool sink_hdcp_capable(igt_output_t *output)
{
char buf[MAX_SINK_HDCP_CAP_BUF_LEN];
@@ -322,26 +562,55 @@ static bool sink_hdcp_capable(igt_output_t *output)
return strstr(buf, "HDCP1.4");
}
+static bool sink_hdcp2_capable(igt_output_t *output)
+{
+ char buf[MAX_SINK_HDCP_CAP_BUF_LEN];
+ int fd;
+
+ fd = igt_debugfs_connector_dir(data.drm_fd, output->name, O_RDONLY);
+ if (fd < 0)
+ return false;
+
+ debugfs_read(fd, "i915_hdcp_sink_capability", buf);
+ close(fd);
+
+ igt_debug("Sink capability: %s\n", buf);
+
+ return strstr(buf, "HDCP2.2");
+}
static void
-test_content_protection(enum igt_commit_style s, bool dpms_test)
+test_content_protection(enum igt_commit_style s, int content_type)
{
igt_display_t *display = &data.display;
igt_output_t *output;
int valid_tests = 0;
+ if (data.cp_tests & CP_MEI_RELOAD)
+ igt_require_f(igt_kmod_is_loaded("mei_hdcp"),
+ "mei_hdcp module is not loaded\n");
+
for_each_connected_output(display, output) {
if (!output->props[IGT_CONNECTOR_CONTENT_PROTECTION])
continue;
+ if (!output->props[IGT_CONNECTOR_HDCP_CONTENT_TYPE] &&
+ content_type)
+ continue;
+
igt_info("CP Test execution on %s\n", output->name);
- if (!sink_hdcp_capable(output)) {
+
+ if (content_type && !sink_hdcp2_capable(output)) {
+ igt_info("\tSkip %s (Sink has no HDCP2.2 support)\n",
+ output->name);
+ continue;
+ } else if (!sink_hdcp_capable(output)) {
igt_info("\tSkip %s (Sink has no HDCP support)\n",
output->name);
continue;
}
- test_content_protection_on_output(output, s, dpms_test);
+ test_content_protection_on_output(output, s, content_type);
valid_tests++;
}
@@ -358,17 +627,69 @@ igt_main
igt_display_require(&data.display, data.drm_fd);
}
- igt_subtest("legacy")
- test_content_protection(COMMIT_LEGACY, false);
+ igt_subtest("legacy") {
+ data.cp_tests = 0;
+ test_content_protection(COMMIT_LEGACY, HDCP_CONTENT_TYPE_0);
+ }
igt_subtest("atomic") {
igt_require(data.display.is_atomic);
- test_content_protection(COMMIT_ATOMIC, false);
+ data.cp_tests = 0;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_0);
}
igt_subtest("atomic-dpms") {
igt_require(data.display.is_atomic);
- test_content_protection(COMMIT_ATOMIC, true);
+ data.cp_tests = CP_DPMS;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_0);
+ }
+
+ igt_subtest("LIC") {
+ igt_require(data.display.is_atomic);
+ data.cp_tests = CP_LIC;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_0);
+ }
+
+ igt_subtest("type1") {
+ igt_require(data.display.is_atomic);
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_1);
+ }
+
+ igt_subtest("mei_interface") {
+ igt_require(data.display.is_atomic);
+ data.cp_tests = CP_MEI_RELOAD;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_1);
+ }
+
+ igt_subtest("content_type_change") {
+ igt_require(data.display.is_atomic);
+ data.cp_tests = CP_TYPE_CHANGE;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_1);
+ }
+
+ igt_subtest("uevent") {
+ igt_require(data.display.is_atomic);
+ data.cp_tests = CP_UEVENT;
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_0);
+ }
+
+ /*
+ * Testing the revocation check through SRM needs a HDCP sink with
+ * programmable Ksvs or we need a uAPI from kernel to read the
+ * connected HDCP sink's Ksv. With that we would be able to add that
+ * Ksv into a SRM and send in for revocation check. Since we dont have
+ * either of these options, we test SRM writing from userspace and
+ * validation of the same at kernel. Something is better than nothing.
+ */
+ igt_subtest("srm") {
+ bool ret;
+
+ igt_require(data.display.is_atomic);
+ data.cp_tests = 0;
+ ret = write_srm_as_fw((const __u8 *)facsimile_srm,
+ sizeof(facsimile_srm));
+ igt_assert_f(ret, "SRM update failed");
+ test_content_protection(COMMIT_ATOMIC, HDCP_CONTENT_TYPE_0);
}
igt_fixture
diff --git a/tests/kms_cursor_edge_walk.c b/tests/kms_cursor_edge_walk.c
index 809dca42..87d17e06 100644
--- a/tests/kms_cursor_edge_walk.c
+++ b/tests/kms_cursor_edge_walk.c
@@ -114,8 +114,6 @@ static void test_edge_pos(data_t *data, int sx, int ex, int y, bool swap_axis)
dx = (ex - sx)/XSTEP;
- igt_pipe_crc_drain(data->pipe_crc);
-
i = 0;
for (x = sx; xdir * (x - ex) <= 0; x += dx) {
diff --git a/tests/kms_hdmi_inject.c b/tests/kms_hdmi_inject.c
index 78684241..52110506 100644
--- a/tests/kms_hdmi_inject.c
+++ b/tests/kms_hdmi_inject.c
@@ -65,8 +65,7 @@ get_connector(int drm_fd, drmModeRes *res)
connector =
drmModeGetConnectorCurrent(drm_fd, res->connectors[i]);
- if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA &&
- connector->connection == DRM_MODE_DISCONNECTED)
+ if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
break;
drmModeFreeConnector(connector);
@@ -79,7 +78,7 @@ get_connector(int drm_fd, drmModeRes *res)
static void
hdmi_inject_4k(int drm_fd, drmModeConnector *connector)
{
- const unsigned char *edid;
+ const struct edid *edid;
struct kmstest_connector_config config;
int ret, cid, i, crtc_mask = -1;
int fb_id;
@@ -140,7 +139,7 @@ hdmi_inject_4k(int drm_fd, drmModeConnector *connector)
static void
hdmi_inject_audio(int drm_fd, drmModeConnector *connector)
{
- const unsigned char *edid;
+ const struct edid *edid;
int fb_id, cid, ret, crtc_mask = -1;
struct igt_fb fb;
struct kmstest_connector_config config;
@@ -203,6 +202,8 @@ igt_main
connector = get_connector(drm_fd, res);
igt_require(connector);
+
+ kmstest_unset_all_crtcs(drm_fd, res);
}
igt_describe("Make sure that 4K modes exposed by DRM match the "
diff --git a/tests/kms_plane_multiple.c b/tests/kms_plane_multiple.c
index 81ed45dd..255cd34a 100644
--- a/tests/kms_plane_multiple.c
+++ b/tests/kms_plane_multiple.c
@@ -317,6 +317,8 @@ test_plane_position_with_output(data_t *data, enum pipe pipe,
for_each_plane_on_pipe(&data->display, pipe, plane)
igt_plane_set_fb(plane, NULL);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
for (int x = 0; x < c; x++)
igt_remove_fb(data->drm_fd, &data->fb[x]);
} while (!err && c < n_planes);
@@ -340,6 +342,8 @@ test_plane_position_with_output(data_t *data, enum pipe pipe,
for_each_plane_on_pipe(&data->display, pipe, plane)
igt_plane_set_fb(plane, NULL);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
for (int x = 0; x < c; x++)
igt_remove_fb(data->drm_fd, &data->fb[x]);
diff --git a/tests/kms_prime.c b/tests/kms_prime.c
new file mode 100644
index 00000000..17599573
--- /dev/null
+++ b/tests/kms_prime.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * 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.
+ */
+
+#include "igt.h"
+#include "igt_vgem.h"
+
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <time.h>
+
+struct crc_info {
+ igt_crc_t crc;
+ char *str;
+ const char *name;
+};
+
+static struct {
+ double r, g, b;
+ uint32_t color;
+ struct crc_info prime_crc, direct_crc;
+} colors[3] = {
+ { .r = 0.0, .g = 0.0, .b = 0.0, .color = 0xff000000 },
+ { .r = 1.0, .g = 1.0, .b = 1.0, .color = 0xffffffff },
+ { .r = 1.0, .g = 0.0, .b = 0.0, .color = 0xffff0000 },
+};
+
+IGT_TEST_DESCRIPTION("Prime tests, focusing on KMS side");
+
+static bool has_prime_import(int fd)
+{
+ uint64_t value;
+
+ if (drmGetCap(fd, DRM_CAP_PRIME, &value))
+ return false;
+
+ return value & DRM_PRIME_CAP_IMPORT;
+}
+
+static bool has_prime_export(int fd)
+{
+ uint64_t value;
+
+ if (drmGetCap(fd, DRM_CAP_PRIME, &value))
+ return false;
+
+ return value & DRM_PRIME_CAP_EXPORT;
+}
+
+static igt_output_t *setup_display(int importer_fd, igt_display_t *display,
+ enum pipe pipe)
+{
+ igt_display_require(display, importer_fd);
+ igt_skip_on(pipe >= display->n_pipes);
+ igt_output_t *output = igt_get_single_output_for_pipe(display, pipe);
+
+ igt_require_f(output, "No connector found for pipe %s\n",
+ kmstest_pipe_name(pipe));
+
+ igt_display_reset(display);
+ igt_output_set_pipe(output, pipe);
+ return output;
+}
+
+static void prepare_scratch(int exporter_fd, struct vgem_bo *scratch,
+ drmModeModeInfo *mode, uint32_t color)
+{
+ uint32_t *ptr;
+
+ scratch->width = mode->hdisplay;
+ scratch->height = mode->vdisplay;
+ scratch->bpp = 32;
+ vgem_create(exporter_fd, scratch);
+
+ ptr = vgem_mmap(exporter_fd, scratch, PROT_WRITE);
+ for (size_t idx = 0; idx < scratch->size / sizeof(*ptr); ++idx)
+ ptr[idx] = color;
+
+ munmap(ptr, scratch->size);
+}
+
+static void prepare_fb(int importer_fd, struct vgem_bo *scratch, struct igt_fb *fb)
+{
+ enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
+ enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
+
+ igt_init_fb(fb, importer_fd, scratch->width, scratch->height,
+ DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ color_encoding, color_range);
+}
+
+static void import_fb(int importer_fd, struct igt_fb *fb,
+ int dmabuf_fd, uint32_t pitch)
+{
+ uint32_t offsets[4] = {}, pitches[4] = {}, handles[4] = {};
+ int ret;
+
+ fb->gem_handle = prime_fd_to_handle(importer_fd, dmabuf_fd);
+
+ handles[0] = fb->gem_handle;
+ pitches[0] = pitch;
+ offsets[0] = 0;
+
+ ret = drmModeAddFB2(importer_fd, fb->width, fb->height,
+ DRM_FORMAT_XRGB8888,
+ handles, pitches, offsets,
+ &fb->fb_id, 0);
+ igt_assert(ret == 0);
+}
+
+static void set_fb(struct igt_fb *fb,
+ igt_display_t *display,
+ igt_output_t *output)
+{
+ igt_plane_t *primary;
+ int ret;
+
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_assert(primary);
+
+ igt_plane_set_fb(primary, fb);
+ ret = igt_display_commit(display);
+
+ igt_assert(ret == 0);
+}
+
+static void collect_crc_for_fb(int importer_fd, struct igt_fb *fb, igt_display_t *display,
+ igt_output_t *output, igt_pipe_crc_t *pipe_crc,
+ uint32_t color, struct crc_info *info)
+{
+ set_fb(fb, display, output);
+ igt_pipe_crc_collect_crc(pipe_crc, &info->crc);
+ info->str = igt_crc_to_string(&info->crc);
+ igt_debug("CRC through '%s' method for %#08x is %s\n",
+ info->name, color, info->str);
+ igt_remove_fb(importer_fd, fb);
+}
+
+static void test_crc(int exporter_fd, int importer_fd)
+{
+ igt_display_t display;
+ igt_output_t *output;
+ igt_pipe_crc_t *pipe_crc;
+ enum pipe pipe = PIPE_A;
+ struct igt_fb fb;
+ int dmabuf_fd;
+ struct vgem_bo scratch = {}; /* despite the name, it suits for any
+ * gem-compatible device
+ * TODO: rename
+ */
+ int i, j;
+ drmModeModeInfo *mode;
+
+ bool crc_equal = false;
+
+ output = setup_display(importer_fd, &display, pipe);
+
+ mode = igt_output_get_mode(output);
+ pipe_crc = igt_pipe_crc_new(importer_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
+
+ for (i = 0; i < ARRAY_SIZE(colors); i++) {
+ prepare_scratch(exporter_fd, &scratch, mode, colors[i].color);
+ dmabuf_fd = prime_handle_to_fd(exporter_fd, scratch.handle);
+ gem_close(exporter_fd, scratch.handle);
+
+ prepare_fb(importer_fd, &scratch, &fb);
+ import_fb(importer_fd, &fb, dmabuf_fd, scratch.pitch);
+ close(dmabuf_fd);
+
+ colors[i].prime_crc.name = "prime";
+ collect_crc_for_fb(importer_fd, &fb, &display, output,
+ pipe_crc, colors[i].color, &colors[i].prime_crc);
+
+ igt_create_color_fb(importer_fd,
+ mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ colors[i].r, colors[i].g, colors[i].b,
+ &fb);
+
+ colors[i].direct_crc.name = "direct";
+ collect_crc_for_fb(importer_fd, &fb, &display, output,
+ pipe_crc, colors[i].color, &colors[i].direct_crc);
+ }
+ igt_pipe_crc_free(pipe_crc);
+
+ igt_debug("CRC table:\n");
+ igt_debug("Color\t\tPrime\t\tDirect\n");
+ for (i = 0; i < ARRAY_SIZE(colors); i++) {
+ igt_debug("%#08x\t%.8s\t%.8s\n", colors[i].color,
+ colors[i].prime_crc.str, colors[i].direct_crc.str);
+ free(colors[i].prime_crc.str);
+ free(colors[i].direct_crc.str);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(colors); i++) {
+ for (j = 0; j < ARRAY_SIZE(colors); j++) {
+ if (i == j) {
+ igt_assert_crc_equal(&colors[i].prime_crc.crc,
+ &colors[j].direct_crc.crc);
+ continue;
+ }
+ crc_equal = igt_check_crc_equal(&colors[i].prime_crc.crc,
+ &colors[j].direct_crc.crc);
+ igt_assert_f(!crc_equal, "CRC should be different");
+ }
+ }
+ igt_display_fini(&display);
+}
+
+static void run_test_crc(int export_chipset, int import_chipset)
+{
+ int importer_fd = -1;
+ int exporter_fd = -1;
+
+ exporter_fd = drm_open_driver(export_chipset);
+ importer_fd = drm_open_driver_master(import_chipset);
+
+ igt_require(has_prime_export(exporter_fd));
+ igt_require(has_prime_import(importer_fd));
+ igt_require_pipe_crc(importer_fd);
+
+ test_crc(exporter_fd, importer_fd);
+ close(importer_fd);
+ close(exporter_fd);
+}
+
+igt_main
+{
+ igt_fixture {
+ kmstest_set_vt_graphics_mode();
+ }
+ igt_describe("Make a dumb buffer inside vgem, fill it, export to another device and compare the CRC");
+ igt_subtest("basic-crc")
+ run_test_crc(DRIVER_VGEM, DRIVER_ANY);
+}
diff --git a/tests/kms_properties.c b/tests/kms_properties.c
index eb9cbdda..18cf96e0 100644
--- a/tests/kms_properties.c
+++ b/tests/kms_properties.c
@@ -91,7 +91,7 @@ static void max_bpc_prop_test(int fd, uint32_t id, uint32_t type, drmModePropert
if (atomic)
req = drmModeAtomicAlloc();
- for ( i = prop->values[0]; i < prop->values[1] ; i++) {
+ for (i = prop->values[0]; i <= prop->values[1]; i++) {
if (!atomic) {
ret = drmModeObjectSetProperty(fd, id, type, prop_id, i);
diff --git a/tests/meson.build b/tests/meson.build
index 34a74025..a7b2b322 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -5,6 +5,7 @@ test_progs = [
'core_getversion',
'core_setmaster_vs_auth',
'debugfs_test',
+ 'dmabuf',
'drm_import_export',
'drm_mm',
'drm_read',
@@ -48,6 +49,7 @@ test_progs = [
'kms_plane_lowres',
'kms_plane_multiple',
'kms_plane_scaling',
+ 'kms_prime',
'kms_prop_blob',
'kms_properties',
'kms_psr',
diff --git a/tests/perf_pmu.c b/tests/perf_pmu.c
index 72b9166a..d392a67d 100644
--- a/tests/perf_pmu.c
+++ b/tests/perf_pmu.c
@@ -1712,116 +1712,110 @@ igt_main
igt_subtest_f("init-sema-%s", e->name)
init(fd, e, I915_SAMPLE_SEMA);
- igt_subtest_group {
- igt_fixture {
- gem_context_has_engine(fd, 0, e->flags);
- }
+ /**
+ * Test that engines show no load when idle.
+ */
+ igt_subtest_f("idle-%s", e->name)
+ single(fd, e, 0);
- /**
- * Test that engines show no load when idle.
- */
- igt_subtest_f("idle-%s", e->name)
- single(fd, e, 0);
-
- /**
- * Test that a single engine reports load correctly.
- */
- igt_subtest_f("busy-%s", e->name)
- single(fd, e, TEST_BUSY);
- igt_subtest_f("busy-idle-%s", e->name)
- single(fd, e, TEST_BUSY | TEST_TRAILING_IDLE);
-
- /**
- * Test that when one engine is loaded other report no
- * load.
- */
- igt_subtest_f("busy-check-all-%s", e->name)
- busy_check_all(fd, e, num_engines, TEST_BUSY);
- igt_subtest_f("busy-idle-check-all-%s", e->name)
- busy_check_all(fd, e, num_engines,
- TEST_BUSY | TEST_TRAILING_IDLE);
-
- /**
- * Test that when all except one engine are loaded all
- * loads are correctly reported.
- */
- igt_subtest_f("most-busy-check-all-%s", e->name)
- most_busy_check_all(fd, e, num_engines,
- TEST_BUSY);
- igt_subtest_f("most-busy-idle-check-all-%s", e->name)
- most_busy_check_all(fd, e, num_engines,
- TEST_BUSY |
- TEST_TRAILING_IDLE);
-
- /**
- * Test that semphore counters report no activity on
- * idle or busy engines.
- */
- igt_subtest_f("idle-no-semaphores-%s", e->name)
- no_sema(fd, e, 0);
-
- igt_subtest_f("busy-no-semaphores-%s", e->name)
- no_sema(fd, e, TEST_BUSY);
-
- igt_subtest_f("busy-idle-no-semaphores-%s", e->name)
- no_sema(fd, e, TEST_BUSY | TEST_TRAILING_IDLE);
-
- /**
- * Test that semaphore waits are correctly reported.
- */
- igt_subtest_f("semaphore-wait-%s", e->name)
- sema_wait(fd, e, TEST_BUSY);
-
- igt_subtest_f("semaphore-wait-idle-%s", e->name)
- sema_wait(fd, e,
- TEST_BUSY | TEST_TRAILING_IDLE);
-
- /**
- * Check that two perf clients do not influence each
- * others observations.
- */
- igt_subtest_f("multi-client-%s", e->name)
- multi_client(fd, e);
-
- /**
- * Check that reported usage is correct when PMU is
- * enabled after the batch is running.
- */
- igt_subtest_f("busy-start-%s", e->name)
- busy_start(fd, e);
-
- /**
- * Check that reported usage is correct when PMU is
- * enabled after two batches are running.
- */
- igt_subtest_f("busy-double-start-%s", e->name) {
- gem_require_contexts(fd);
- busy_double_start(fd, e);
- }
+ /**
+ * Test that a single engine reports load correctly.
+ */
+ igt_subtest_f("busy-%s", e->name)
+ single(fd, e, TEST_BUSY);
+ igt_subtest_f("busy-idle-%s", e->name)
+ single(fd, e, TEST_BUSY | TEST_TRAILING_IDLE);
- /**
- * Check that the PMU can be safely enabled in face of
- * interrupt-heavy engine load.
- */
- igt_subtest_f("enable-race-%s", e->name)
- test_enable_race(fd, e);
-
- /**
- * Check engine busyness accuracy is as expected.
- */
- for (i = 0; i < ARRAY_SIZE(pct); i++) {
- igt_subtest_f("busy-accuracy-%u-%s",
- pct[i], e->name)
- accuracy(fd, e, pct[i], 10);
- }
+ /**
+ * Test that when one engine is loaded other report no
+ * load.
+ */
+ igt_subtest_f("busy-check-all-%s", e->name)
+ busy_check_all(fd, e, num_engines, TEST_BUSY);
+ igt_subtest_f("busy-idle-check-all-%s", e->name)
+ busy_check_all(fd, e, num_engines,
+ TEST_BUSY | TEST_TRAILING_IDLE);
+
+ /**
+ * Test that when all except one engine are loaded all
+ * loads are correctly reported.
+ */
+ igt_subtest_f("most-busy-check-all-%s", e->name)
+ most_busy_check_all(fd, e, num_engines,
+ TEST_BUSY);
+ igt_subtest_f("most-busy-idle-check-all-%s", e->name)
+ most_busy_check_all(fd, e, num_engines,
+ TEST_BUSY |
+ TEST_TRAILING_IDLE);
- igt_subtest_f("busy-hang-%s", e->name) {
- igt_hang_t hang = igt_allow_hang(fd, 0, 0);
+ /**
+ * Test that semphore counters report no activity on
+ * idle or busy engines.
+ */
+ igt_subtest_f("idle-no-semaphores-%s", e->name)
+ no_sema(fd, e, 0);
- single(fd, e, TEST_BUSY | FLAG_HANG);
+ igt_subtest_f("busy-no-semaphores-%s", e->name)
+ no_sema(fd, e, TEST_BUSY);
- igt_disallow_hang(fd, hang);
- }
+ igt_subtest_f("busy-idle-no-semaphores-%s", e->name)
+ no_sema(fd, e, TEST_BUSY | TEST_TRAILING_IDLE);
+
+ /**
+ * Test that semaphore waits are correctly reported.
+ */
+ igt_subtest_f("semaphore-wait-%s", e->name)
+ sema_wait(fd, e, TEST_BUSY);
+
+ igt_subtest_f("semaphore-wait-idle-%s", e->name)
+ sema_wait(fd, e,
+ TEST_BUSY | TEST_TRAILING_IDLE);
+
+ /**
+ * Check that two perf clients do not influence each
+ * others observations.
+ */
+ igt_subtest_f("multi-client-%s", e->name)
+ multi_client(fd, e);
+
+ /**
+ * Check that reported usage is correct when PMU is
+ * enabled after the batch is running.
+ */
+ igt_subtest_f("busy-start-%s", e->name)
+ busy_start(fd, e);
+
+ /**
+ * Check that reported usage is correct when PMU is
+ * enabled after two batches are running.
+ */
+ igt_subtest_f("busy-double-start-%s", e->name) {
+ gem_require_contexts(fd);
+ busy_double_start(fd, e);
+ }
+
+ /**
+ * Check that the PMU can be safely enabled in face of
+ * interrupt-heavy engine load.
+ */
+ igt_subtest_f("enable-race-%s", e->name)
+ test_enable_race(fd, e);
+
+ /**
+ * Check engine busyness accuracy is as expected.
+ */
+ for (i = 0; i < ARRAY_SIZE(pct); i++) {
+ igt_subtest_f("busy-accuracy-%u-%s",
+ pct[i], e->name)
+ accuracy(fd, e, pct[i], 10);
+ }
+
+ igt_subtest_f("busy-hang-%s", e->name) {
+ igt_hang_t hang = igt_allow_hang(fd, 0, 0);
+
+ single(fd, e, TEST_BUSY | FLAG_HANG);
+
+ igt_disallow_hang(fd, hang);
}
/**
@@ -1901,19 +1895,12 @@ igt_main
}
__for_each_physical_engine(render_fd, e) {
- igt_subtest_group {
- igt_fixture {
- gem_context_has_engine(render_fd,
- 0, e->flags);
- }
-
- igt_subtest_f("render-node-busy-%s", e->name)
- single(render_fd, e, TEST_BUSY);
- igt_subtest_f("render-node-busy-idle-%s",
- e->name)
- single(render_fd, e,
- TEST_BUSY | TEST_TRAILING_IDLE);
- }
+ igt_subtest_f("render-node-busy-%s", e->name)
+ single(render_fd, e, TEST_BUSY);
+ igt_subtest_f("render-node-busy-idle-%s",
+ e->name)
+ single(render_fd, e,
+ TEST_BUSY | TEST_TRAILING_IDLE);
}
igt_fixture {