xref: /linux/drivers/gpu/drm/tests/drm_kunit_helpers.c (revision 6eb0ea28c8e80ead03f08cf8cbdacf08d3073bd6)
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