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/resource.h> 9 10 #include <linux/device.h> 11 #include <linux/platform_device.h> 12 13 #define KUNIT_DEVICE_NAME "drm-kunit-mock-device" 14 15 static const struct drm_mode_config_funcs drm_mode_config_funcs = { 16 }; 17 18 static int fake_probe(struct platform_device *pdev) 19 { 20 return 0; 21 } 22 23 static struct platform_driver fake_platform_driver = { 24 .probe = fake_probe, 25 .driver = { 26 .name = KUNIT_DEVICE_NAME, 27 }, 28 }; 29 30 KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_driver_unregister, 31 platform_driver_unregister, 32 struct platform_driver *); 33 KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_device_put, 34 platform_device_put, 35 struct platform_device *); 36 KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_device_del, 37 platform_device_del, 38 struct platform_device *); 39 40 /** 41 * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test 42 * @test: The test context object 43 * 44 * This allocates a fake struct &device to create a mock for a KUnit 45 * test. The device will also be bound to a fake driver. It will thus be 46 * able to leverage the usual infrastructure and most notably the 47 * device-managed resources just like a "real" device. 48 * 49 * Resources will be cleaned up automatically, but the removal can be 50 * forced using @drm_kunit_helper_free_device. 51 * 52 * Returns: 53 * A pointer to the new device, or an ERR_PTR() otherwise. 54 */ 55 struct device *drm_kunit_helper_alloc_device(struct kunit *test) 56 { 57 struct platform_device *pdev; 58 int ret; 59 60 ret = platform_driver_register(&fake_platform_driver); 61 KUNIT_ASSERT_EQ(test, ret, 0); 62 63 ret = kunit_add_action_or_reset(test, 64 kunit_action_platform_driver_unregister, 65 &fake_platform_driver); 66 KUNIT_ASSERT_EQ(test, ret, 0); 67 68 pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE); 69 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 70 71 ret = kunit_add_action_or_reset(test, 72 kunit_action_platform_device_put, 73 pdev); 74 KUNIT_ASSERT_EQ(test, ret, 0); 75 76 ret = platform_device_add(pdev); 77 KUNIT_ASSERT_EQ(test, ret, 0); 78 79 ret = kunit_add_action_or_reset(test, 80 kunit_action_platform_device_del, 81 pdev); 82 KUNIT_ASSERT_EQ(test, ret, 0); 83 84 return &pdev->dev; 85 } 86 EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device); 87 88 /** 89 * drm_kunit_helper_free_device - Frees a mock device 90 * @test: The test context object 91 * @dev: The device to free 92 * 93 * Frees a device allocated with drm_kunit_helper_alloc_device(). 94 */ 95 void drm_kunit_helper_free_device(struct kunit *test, struct device *dev) 96 { 97 struct platform_device *pdev = to_platform_device(dev); 98 99 kunit_release_action(test, 100 kunit_action_platform_device_del, 101 pdev); 102 103 kunit_release_action(test, 104 kunit_action_platform_device_put, 105 pdev); 106 107 kunit_release_action(test, 108 kunit_action_platform_driver_unregister, 109 &fake_platform_driver); 110 } 111 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device); 112 113 struct drm_device * 114 __drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test, 115 struct device *dev, 116 size_t size, size_t offset, 117 const struct drm_driver *driver) 118 { 119 struct drm_device *drm; 120 void *container; 121 int ret; 122 123 container = __devm_drm_dev_alloc(dev, driver, size, offset); 124 if (IS_ERR(container)) 125 return ERR_CAST(container); 126 127 drm = container + offset; 128 drm->mode_config.funcs = &drm_mode_config_funcs; 129 130 ret = drmm_mode_config_init(drm); 131 if (ret) 132 return ERR_PTR(ret); 133 134 return drm; 135 } 136 EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver); 137 138 static void action_drm_release_context(void *ptr) 139 { 140 struct drm_modeset_acquire_ctx *ctx = ptr; 141 142 drm_modeset_drop_locks(ctx); 143 drm_modeset_acquire_fini(ctx); 144 } 145 146 /** 147 * drm_kunit_helper_acquire_ctx_alloc - Allocates an acquire context 148 * @test: The test context object 149 * 150 * Allocates and initializes a modeset acquire context. 151 * 152 * The context is tied to the kunit test context, so we must not call 153 * drm_modeset_acquire_fini() on it, it will be done so automatically. 154 * 155 * Returns: 156 * An ERR_PTR on error, a pointer to the newly allocated context otherwise 157 */ 158 struct drm_modeset_acquire_ctx * 159 drm_kunit_helper_acquire_ctx_alloc(struct kunit *test) 160 { 161 struct drm_modeset_acquire_ctx *ctx; 162 int ret; 163 164 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 165 KUNIT_ASSERT_NOT_NULL(test, ctx); 166 167 drm_modeset_acquire_init(ctx, 0); 168 169 ret = kunit_add_action_or_reset(test, 170 action_drm_release_context, 171 ctx); 172 if (ret) 173 return ERR_PTR(ret); 174 175 return ctx; 176 } 177 EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc); 178 179 static void kunit_action_drm_atomic_state_put(void *ptr) 180 { 181 struct drm_atomic_state *state = ptr; 182 183 drm_atomic_state_put(state); 184 } 185 186 /** 187 * drm_kunit_helper_atomic_state_alloc - Allocates an atomic state 188 * @test: The test context object 189 * @drm: The device to alloc the state for 190 * @ctx: Locking context for that atomic update 191 * 192 * Allocates a empty atomic state. 193 * 194 * The state is tied to the kunit test context, so we must not call 195 * drm_atomic_state_put() on it, it will be done so automatically. 196 * 197 * Returns: 198 * An ERR_PTR on error, a pointer to the newly allocated state otherwise 199 */ 200 struct drm_atomic_state * 201 drm_kunit_helper_atomic_state_alloc(struct kunit *test, 202 struct drm_device *drm, 203 struct drm_modeset_acquire_ctx *ctx) 204 { 205 struct drm_atomic_state *state; 206 int ret; 207 208 state = drm_atomic_state_alloc(drm); 209 if (!state) 210 return ERR_PTR(-ENOMEM); 211 212 ret = kunit_add_action_or_reset(test, 213 kunit_action_drm_atomic_state_put, 214 state); 215 if (ret) 216 return ERR_PTR(ret); 217 218 state->acquire_ctx = ctx; 219 220 return state; 221 } 222 EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc); 223 224 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>"); 225 MODULE_LICENSE("GPL"); 226