diff options
author | Haibo Huang <hhb@google.com> | 2019-08-22 11:30:45 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-08-22 11:30:45 -0700 |
commit | 206a8e3febc313c234301319fe1591dc3f92d812 (patch) | |
tree | 5d6743a29d41d23b45ed604e4b3b9e87e7cfc25c | |
parent | 4a12edecbca8c11abd6520a664e300f370d41397 (diff) | |
parent | 9149125daf306cd5b3b2688b53a779052fc88d93 (diff) | |
download | platform_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
53 files changed, 1969 insertions, 447 deletions
@@ -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 } } @@ -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, ¶m); + 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, ¤t_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 { |