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