Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/tests/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 13 kB image not shown  

Quelle  drm_bridge_test.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Kunit test for drm_bridge functions
 */

#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_bridge_helper.h>
#include <drm/drm_kunit_helpers.h>

#include <kunit/device.h>
#include <kunit/test.h>

/*
 * Mimick the typical "private" struct defined by a bridge driver, which
 * embeds a bridge plus other fields.
 *
 * Having at least one member before @bridge ensures we test non-zero
 * @bridge offset.
 */

struct drm_bridge_priv {
 unsigned int enable_count;
 unsigned int disable_count;
 struct drm_bridge bridge;
 void *data;
};

struct drm_bridge_init_priv {
 struct drm_device drm;
 /** @dev: device, only for tests not needing a whole drm_device */
 struct device *dev;
 struct drm_plane *plane;
 struct drm_crtc *crtc;
 struct drm_encoder encoder;
 struct drm_bridge_priv *test_bridge;
 struct drm_connector *connector;
 bool destroyed;
};

static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge)
{
 return container_of(bridge, struct drm_bridge_priv, bridge);
}

static void drm_test_bridge_priv_destroy(struct drm_bridge *bridge)
{
 struct drm_bridge_priv *bridge_priv = bridge_to_priv(bridge);
 struct drm_bridge_init_priv *priv = (struct drm_bridge_init_priv *)bridge_priv->data;

 priv->destroyed = true;
}

static void drm_test_bridge_enable(struct drm_bridge *bridge)
{
 struct drm_bridge_priv *priv = bridge_to_priv(bridge);

 priv->enable_count++;
}

static void drm_test_bridge_disable(struct drm_bridge *bridge)
{
 struct drm_bridge_priv *priv = bridge_to_priv(bridge);

 priv->disable_count++;
}

static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
 .destroy  = drm_test_bridge_priv_destroy,
 .enable   = drm_test_bridge_enable,
 .disable  = drm_test_bridge_disable,
};

static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
       struct drm_atomic_state *state)
{
 struct drm_bridge_priv *priv = bridge_to_priv(bridge);

 priv->enable_count++;
}

static void drm_test_bridge_atomic_disable(struct drm_bridge *bridge,
        struct drm_atomic_state *state)
{
 struct drm_bridge_priv *priv = bridge_to_priv(bridge);

 priv->disable_count++;
}

static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
 .destroy  = drm_test_bridge_priv_destroy,
 .atomic_enable  = drm_test_bridge_atomic_enable,
 .atomic_disable  = drm_test_bridge_atomic_disable,
 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 .atomic_reset  = drm_atomic_helper_bridge_reset,
};

KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
       drm_bridge_remove,
       struct drm_bridge *);

static int drm_kunit_bridge_add(struct kunit *test,
    struct drm_bridge *bridge)
{
 drm_bridge_add(bridge);

 return kunit_add_action_or_reset(test,
      drm_bridge_remove_wrapper,
      bridge);
}

static struct drm_bridge_init_priv *
drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
{
 struct drm_bridge_init_priv *priv;
 struct drm_encoder *enc;
 struct drm_bridge *bridge;
 struct drm_device *drm;
 struct device *dev;
 int ret;

 dev = drm_kunit_helper_alloc_device(test);
 if (IS_ERR(dev))
  return ERR_CAST(dev);

 priv = drm_kunit_helper_alloc_drm_device(test, dev,
       struct drm_bridge_init_priv, drm,
       DRIVER_MODESET | DRIVER_ATOMIC);
 if (IS_ERR(priv))
  return ERR_CAST(priv);

 priv->test_bridge = devm_drm_bridge_alloc(dev, struct drm_bridge_priv, bridge, funcs);
 if (IS_ERR(priv->test_bridge))
  return ERR_CAST(priv->test_bridge);

 priv->test_bridge->data = priv;

 drm = &priv->drm;
 priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
           NULL,
           NULL,
           NULL, 0,
           NULL);
 if (IS_ERR(priv->plane))
  return ERR_CAST(priv->plane);

 priv->crtc = drm_kunit_helper_create_crtc(test, drm,
        priv->plane, NULL,
        NULL,
        NULL);
 if (IS_ERR(priv->crtc))
  return ERR_CAST(priv->crtc);

 enc = &priv->encoder;
 ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
 if (ret)
  return ERR_PTR(ret);

 enc->possible_crtcs = drm_crtc_mask(priv->crtc);

 bridge = &priv->test_bridge->bridge;
 bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;

 ret = drm_kunit_bridge_add(test, bridge);
 if (ret)
  return ERR_PTR(ret);

 ret = drm_bridge_attach(enc, bridge, NULL, 0);
 if (ret)
  return ERR_PTR(ret);

 priv->connector = drm_bridge_connector_init(drm, enc);
 if (IS_ERR(priv->connector))
  return ERR_CAST(priv->connector);

 drm_connector_attach_encoder(priv->connector, enc);

 drm_mode_config_reset(drm);

 return priv;
}

/*
 * Test that drm_bridge_get_current_state() returns the last committed
 * state for an atomic bridge.
 */

static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
{
 struct drm_modeset_acquire_ctx ctx;
 struct drm_bridge_init_priv *priv;
 struct drm_bridge_state *curr_bridge_state;
 struct drm_bridge_state *bridge_state;
 struct drm_atomic_state *state;
 struct drm_bridge *bridge;
 struct drm_device *drm;
 int ret;

 priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 drm_modeset_acquire_init(&ctx, 0);

 drm = &priv->drm;
 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);

retry_commit:
 bridge = &priv->test_bridge->bridge;
 bridge_state = drm_atomic_get_bridge_state(state, bridge);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);

 ret = drm_atomic_commit(state);
 if (ret == -EDEADLK) {
  drm_atomic_state_clear(state);
  drm_modeset_backoff(&ctx);
  goto retry_commit;
 }
 KUNIT_ASSERT_EQ(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 drm_modeset_acquire_init(&ctx, 0);

retry_state:
 ret = drm_modeset_lock(&bridge->base.lock, &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_state;
 }

 curr_bridge_state = drm_bridge_get_current_state(bridge);
 KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);

 drm_modeset_unlock(&bridge->base.lock);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);
}

/*
 * Test that drm_bridge_get_current_state() returns NULL for a
 * non-atomic bridge.
 */

static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
{
 struct drm_bridge_init_priv *priv;
 struct drm_bridge *bridge;

 priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 /*
 * NOTE: Strictly speaking, we should take the bridge->base.lock
 * before calling that function. However, bridge->base is only
 * initialized if the bridge is atomic, while we explicitly
 * initialize one that isn't there.
 *
 * In order to avoid unnecessary warnings, let's skip the
 * locking. The function would return NULL in all cases anyway,
 * so we don't really have any concurrency to worry about.
 */

 bridge = &priv->test_bridge->bridge;
 KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
}

static struct kunit_case drm_bridge_get_current_state_tests[] = {
 KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
 KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
 { }
};


static struct kunit_suite drm_bridge_get_current_state_test_suite = {
 .name = "drm_test_bridge_get_current_state",
 .test_cases = drm_bridge_get_current_state_tests,
};

/*
 * Test that an atomic bridge is properly power-cycled when calling
 * drm_bridge_helper_reset_crtc().
 */

static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
{
 struct drm_modeset_acquire_ctx ctx;
 struct drm_bridge_init_priv *priv;
 struct drm_display_mode *mode;
 struct drm_bridge_priv *bridge_priv;
 int ret;

 priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);

 drm_modeset_acquire_init(&ctx, 0);

retry_commit:
 ret = drm_kunit_helper_enable_crtc_connector(test,
           &priv->drm, priv->crtc,
           priv->connector,
           mode,
           &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_commit;
 }
 KUNIT_ASSERT_EQ(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 bridge_priv = priv->test_bridge;
 KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
 KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);

 drm_modeset_acquire_init(&ctx, 0);

retry_reset:
 ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_reset;
 }
 KUNIT_ASSERT_EQ(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
 KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
}

/*
 * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
 * bridge will fail and not call the enable / disable callbacks
 */

static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
{
 struct drm_modeset_acquire_ctx ctx;
 struct drm_bridge_init_priv *priv;
 struct drm_display_mode *mode;
 struct drm_bridge_priv *bridge_priv;
 int ret;

 priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);

 bridge_priv = priv->test_bridge;
 KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 0);
 KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);

 drm_modeset_acquire_init(&ctx, 0);

retry_reset:
 ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_reset;
 }
 KUNIT_EXPECT_LT(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 0);
 KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 0);
}

/*
 * Test that a non-atomic bridge is properly power-cycled when calling
 * drm_bridge_helper_reset_crtc().
 */

static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
{
 struct drm_modeset_acquire_ctx ctx;
 struct drm_bridge_init_priv *priv;
 struct drm_display_mode *mode;
 struct drm_bridge_priv *bridge_priv;
 int ret;

 priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);

 drm_modeset_acquire_init(&ctx, 0);

retry_commit:
 ret = drm_kunit_helper_enable_crtc_connector(test,
           &priv->drm, priv->crtc,
           priv->connector,
           mode,
           &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_commit;
 }
 KUNIT_ASSERT_EQ(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 bridge_priv = priv->test_bridge;
 KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
 KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);

 drm_modeset_acquire_init(&ctx, 0);

retry_reset:
 ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
 if (ret == -EDEADLK) {
  drm_modeset_backoff(&ctx);
  goto retry_reset;
 }
 KUNIT_ASSERT_EQ(test, ret, 0);

 drm_modeset_drop_locks(&ctx);
 drm_modeset_acquire_fini(&ctx);

 KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
 KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
}

static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
 KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
 KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
 KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
 { }
};

static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
 .name = "drm_test_bridge_helper_reset_crtc",
 .test_cases = drm_bridge_helper_reset_crtc_tests,
};

static int drm_test_bridge_alloc_init(struct kunit *test)
{
 struct drm_bridge_init_priv *priv;

 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);

 priv->dev = kunit_device_register(test, "drm-bridge-dev");
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);

 test->priv = priv;

 priv->test_bridge = devm_drm_bridge_alloc(priv->dev, struct drm_bridge_priv, bridge,
        &drm_test_bridge_atomic_funcs);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->test_bridge);

 priv->test_bridge->data = priv;

 KUNIT_ASSERT_FALSE(test, priv->destroyed);

 return 0;
}

/*
 * Test that a bridge is freed when the device is destroyed in lack of
 * other drm_bridge_get/put() operations.
 */

static void drm_test_drm_bridge_alloc_basic(struct kunit *test)
{
 struct drm_bridge_init_priv *priv = test->priv;

 KUNIT_ASSERT_FALSE(test, priv->destroyed);

 kunit_device_unregister(test, priv->dev);
 KUNIT_EXPECT_TRUE(test, priv->destroyed);
}

/*
 * Test that a bridge is not freed when the device is destroyed when there
 * is still a reference to it, and freed when that reference is put.
 */

static void drm_test_drm_bridge_alloc_get_put(struct kunit *test)
{
 struct drm_bridge_init_priv *priv = test->priv;

 KUNIT_ASSERT_FALSE(test, priv->destroyed);

 drm_bridge_get(&priv->test_bridge->bridge);
 KUNIT_EXPECT_FALSE(test, priv->destroyed);

 kunit_device_unregister(test, priv->dev);
 KUNIT_EXPECT_FALSE(test, priv->destroyed);

 drm_bridge_put(&priv->test_bridge->bridge);
 KUNIT_EXPECT_TRUE(test, priv->destroyed);
}

static struct kunit_case drm_bridge_alloc_tests[] = {
 KUNIT_CASE(drm_test_drm_bridge_alloc_basic),
 KUNIT_CASE(drm_test_drm_bridge_alloc_get_put),
 { }
};

static struct kunit_suite drm_bridge_alloc_test_suite = {
 .name = "drm_bridge_alloc",
 .init = drm_test_bridge_alloc_init,
 .test_cases = drm_bridge_alloc_tests,
};

kunit_test_suites(
 &drm_bridge_get_current_state_test_suite,
 &drm_bridge_helper_reset_crtc_test_suite,
 &drm_bridge_alloc_test_suite,
);

MODULE_AUTHOR("Maxime Ripard ");
MODULE_AUTHOR("Luca Ceresoli ");

MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
MODULE_LICENSE("GPL");

Messung V0.5
C=97 H=99 G=97

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.