[PATCH 2/2] tests: Test suspend and resume on active pipelines

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Kieran Bingham <kieran.bingham+renesas@xxxxxxxxxxxxxxxx>

Utilise the CONFIG_PM_DEBUG framework to perform automated suspend
testing of the hardware devices.

Generate active frames on a plane, and ensure that flip notifications
are received both before a suspend, and then following a resume action.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@xxxxxxxxxxxxxxxx>
---
 tests/kms-test-suspend-resume.py | 189 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 189 insertions(+)
 create mode 100755 tests/kms-test-suspend-resume.py

diff --git a/tests/kms-test-suspend-resume.py b/tests/kms-test-suspend-resume.py
new file mode 100755
index 000000000000..69c66e269cdd
--- /dev/null
+++ b/tests/kms-test-suspend-resume.py
@@ -0,0 +1,189 @@
+#!/usr/bin/python3
+
+import kmstest
+import os
+import pykms
+import threading
+
+
+class PageFlipper(object):
+    """Test page flipping on a connector with the default mode."""
+
+    BAR_WIDTH = 20
+    BAR_SPEED = 8
+
+    def __init__(self, test):
+        self.test = test
+        self.logger = test.logger
+        self.loop = test.loop
+        self.card = test.card
+
+        # Register ourselves as the parent test's flip handler ... :S
+        test.handle_page_flip = self.handle_page_flip
+
+    def handle_page_flip(self, frame, time):
+        self.flips += 1
+
+        if self.flips == 1:
+            self.logger.log("first page flip frame %u time %f" % (frame, time))
+            self.frame_start = frame
+            self.time_start = time
+
+        if self.stop_requested:
+            self.logger.log("last page flip frame %u time %f" % (frame, time))
+            self.frame_end = frame
+            self.time_end = time
+            self.loop.stop()
+            self.stop_requested = False
+            return
+
+        fb = self.fbs[self.front_buf]
+        self.front_buf = self.front_buf ^ 1
+
+        old_xpos = (self.bar_xpos - self.BAR_SPEED) % (fb.width - self.BAR_WIDTH)
+        new_xpos = (self.bar_xpos + self.BAR_SPEED) % (fb.width - self.BAR_WIDTH)
+        self.bar_xpos = new_xpos
+
+        pykms.draw_color_bar(fb, old_xpos, new_xpos, self.BAR_WIDTH)
+
+        source = kmstest.Rect(0, 0, fb.width, fb.height)
+        destination = kmstest.Rect(0, 0, fb.width, fb.height)
+        self.test.atomic_plane_set(self.plane, self.crtc, source, destination, fb)
+
+    def stop_page_flip(self):
+        self.stop_requested = True
+
+    def run(self, connector):
+        # Skip disconnected connectors
+        if not connector.connected():
+            return self.test.skip("unconnected connector")
+
+        # Find a CRTC suitable for the connector
+        crtc = connector.get_current_crtc()
+        if not crtc:
+            crtcs = connector.get_possible_crtcs()
+            if len(crtcs) == 0:
+                pass
+
+            crtc = crtcs[0]
+
+        self.crtc = crtc
+
+        # Find a plane suitable for the CRTC
+        for plane in self.card.planes:
+            if plane.supports_crtc(crtc):
+                self.plane = plane
+                break
+        else:
+            return self.test.skip("no plane available for CRTC %u" % crtc.id)
+
+        # Get the default mode for the connector
+        try:
+            mode = connector.get_default_mode()
+        except ValueError:
+            return self.test.skip("no mode available")
+
+        self.logger.log("Testing connector %s, CRTC %u, plane %u, mode %s" %
+                        (connector.fullname, crtc.id, self.plane.id, mode.name))
+
+        # Initialise run state
+        self.bar_xpos = 0
+        self.front_buf = 0
+        self.frame_start = 0
+        self.frame_end = 0
+        self.time_start = 0
+        self.time_end = 0
+        self.flips = 0
+        self.previous_flips = 0
+        self.stop_requested = False
+
+        # Create two frame buffers
+        self.fbs = []
+        for i in range(2):
+            self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24"))
+
+        # Set the mode and perform the initial page flip
+        ret = self.test.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
+        if ret < 0:
+            return self.test.fail("atomic mode set failed with %d" % ret)
+
+        # Flipper is now running!
+        return True
+
+    def is_running(self):
+            running = self.flips != self.previous_flips
+            self.previous_flips = self.flips
+            return running
+
+    def verify_completion(self):
+            if not self.flips:
+                return self.test.fail("No page flip registered")
+
+            if self.stop_requested:
+                return self.test.fail("Last page flip not registered")
+
+            frames = self.frame_end - self.frame_start + 1
+            interval = self.time_end - self.time_start
+            self.logger.log("Frame rate: %f (%u/%u frames in %f s)" %
+                            (frames / interval, self.flips, frames, interval))
+
+            return self.test.success()
+
+
+class PMTest(object):
+    def supported(self):
+        return os.path.exists("/sys/power/pm_test")
+
+    def suspend(self, mode):
+        with open('/sys/power/pm_test', 'a') as pm_test:
+            pm_test.write(mode + '\n')
+
+        with open('/sys/power/state', 'a') as state:
+            state.write('mem' + '\n')
+
+
+class SuspendResume(kmstest.KMSTest):
+    """Test suspend resume cycle while the display is active."""
+
+    def main(self):
+        # The PageFlipper will register itself as our Page Flip Handler
+        self.flipper = PageFlipper(self)
+
+        # First ensure that we have CONFIG_PM_DEBUG. We cannot continue without
+        self.start("dependencies for suspend-resume")
+        if not PMTest().supported():
+            self.skip("CONFIG_PM_DEBUG not available")
+            return
+
+        self.success()
+
+        for connector in self.card.connectors:
+            self.start("suspend resume with connector %s" % connector.fullname)
+
+            status = self.flipper.run(connector)
+            if status is not True:
+                continue
+
+            # Let the display pipeline get started
+            self.run(5)
+
+            if not self.flipper.is_running():
+                self.fail("Page flip not active before suspend")
+                continue
+
+            # Try a suspend cycle
+            PMTest().suspend('devices')
+
+            # Reset the run check, and verify the pipeline is still active
+            self.flipper.is_running()
+            self.run(5)
+            if not self.flipper.is_running():
+                self.fail("Page flip not active after suspend")
+                continue
+
+            # Test completed, verify we stop correctly
+            self.flipper.stop_page_flip()
+            self.run(1)
+            self.flipper.verify_completion()
+
+SuspendResume().execute()
-- 
2.7.4




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux