1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <drm/drm_atomic.h> 4 #include <drm/drm_drv.h> 5 #include <drm/drm_kunit_helpers.h> 6 #include <drm/drm_managed.h> 7 8 #include <kunit/device.h> 9 #include <kunit/resource.h> 10 11 #include <linux/device.h> 12 #include <linux/platform_device.h> 13 14 #define KUNIT_DEVICE_NAME "drm-kunit-mock-device" 15 16 static const struct drm_mode_config_funcs drm_mode_config_funcs = { 17 }; 18 19 /** 20 * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test 21 * @test: The test context object 22 * 23 * This allocates a fake struct &device to create a mock for a KUnit 24 * test. The device will also be bound to a fake driver. It will thus be 25 * able to leverage the usual infrastructure and most notably the 26 * device-managed resources just like a "real" device. 27 * 28 * Resources will be cleaned up automatically, but the removal can be 29 * forced using @drm_kunit_helper_free_device. 30 * 31 * Returns: 32 * A pointer to the new device, or an ERR_PTR() otherwise. 33 */ 34 struct device *drm_kunit_helper_alloc_device(struct kunit *test) 35 { 36 return kunit_device_register(test, KUNIT_DEVICE_NAME); 37 } 38 EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device); 39 40 /** 41 * drm_kunit_helper_free_device - Frees a mock device 42 * @test: The test context object 43 * @dev: The device to free 44 * 45 * Frees a device allocated with drm_kunit_helper_alloc_device(). 46 */ 47 void drm_kunit_helper_free_device(struct kunit *test, struct device *dev) 48 { 49 kunit_device_unregister(test, dev); 50 } 51 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device); 52 53 struct drm_device * 54 __drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test, 55 struct device *dev, 56 size_t size, size_t offset, 57 const struct drm_driver *driver) 58 { 59 struct drm_device *drm; 60 void *container; 61 int ret; 62 63 container = __devm_drm_dev_alloc(dev, driver, size, offset); 64 if (IS_ERR(container)) 65 return ERR_CAST(container); 66 67 drm = container + offset; 68 drm->mode_config.funcs = &drm_mode_config_funcs; 69 70 ret = drmm_mode_config_init(drm); 71 if (ret) 72 return ERR_PTR(ret); 73 74 return drm; 75 } 76 EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver); 77 78 static void action_drm_release_context(void *ptr) 79 { 80 struct drm_modeset_acquire_ctx *ctx = ptr; 81 82 drm_modeset_drop_locks(ctx); 83 drm_modeset_acquire_fini(ctx); 84 } 85 86 /** 87 * drm_kunit_helper_acquire_ctx_alloc - Allocates an acquire context 88 * @test: The test context object 89 * 90 * Allocates and initializes a modeset acquire context. 91 * 92 * The context is tied to the kunit test context, so we must not call 93 * drm_modeset_acquire_fini() on it, it will be done so automatically. 94 * 95 * Returns: 96 * An ERR_PTR on error, a pointer to the newly allocated context otherwise 97 */ 98 struct drm_modeset_acquire_ctx * 99 drm_kunit_helper_acquire_ctx_alloc(struct kunit *test) 100 { 101 struct drm_modeset_acquire_ctx *ctx; 102 int ret; 103 104 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 105 KUNIT_ASSERT_NOT_NULL(test, ctx); 106 107 drm_modeset_acquire_init(ctx, 0); 108 109 ret = kunit_add_action_or_reset(test, 110 action_drm_release_context, 111 ctx); 112 if (ret) 113 return ERR_PTR(ret); 114 115 return ctx; 116 } 117 EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc); 118 119 static void kunit_action_drm_atomic_state_put(void *ptr) 120 { 121 struct drm_atomic_state *state = ptr; 122 123 drm_atomic_state_put(state); 124 } 125 126 /** 127 * drm_kunit_helper_atomic_state_alloc - Allocates an atomic state 128 * @test: The test context object 129 * @drm: The device to alloc the state for 130 * @ctx: Locking context for that atomic update 131 * 132 * Allocates a empty atomic state. 133 * 134 * The state is tied to the kunit test context, so we must not call 135 * drm_atomic_state_put() on it, it will be done so automatically. 136 * 137 * Returns: 138 * An ERR_PTR on error, a pointer to the newly allocated state otherwise 139 */ 140 struct drm_atomic_state * 141 drm_kunit_helper_atomic_state_alloc(struct kunit *test, 142 struct drm_device *drm, 143 struct drm_modeset_acquire_ctx *ctx) 144 { 145 struct drm_atomic_state *state; 146 int ret; 147 148 state = drm_atomic_state_alloc(drm); 149 if (!state) 150 return ERR_PTR(-ENOMEM); 151 152 ret = kunit_add_action_or_reset(test, 153 kunit_action_drm_atomic_state_put, 154 state); 155 if (ret) 156 return ERR_PTR(ret); 157 158 state->acquire_ctx = ctx; 159 160 return state; 161 } 162 EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc); 163 164 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>"); 165 MODULE_LICENSE("GPL"); 166