Line data Source code
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 5 : static int fake_probe(struct platform_device *pdev)
19 : {
20 5 : 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 5 : static void kunit_action_platform_driver_unregister(void *ptr)
31 : {
32 5 : struct platform_driver *drv = ptr;
33 :
34 5 : platform_driver_unregister(drv);
35 :
36 5 : }
37 :
38 5 : static void kunit_action_platform_device_put(void *ptr)
39 : {
40 5 : struct platform_device *pdev = ptr;
41 :
42 5 : platform_device_put(pdev);
43 5 : }
44 :
45 5 : static void kunit_action_platform_device_del(void *ptr)
46 : {
47 5 : struct platform_device *pdev = ptr;
48 :
49 5 : platform_device_del(pdev);
50 5 : }
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 : */
67 5 : struct device *drm_kunit_helper_alloc_device(struct kunit *test)
68 : {
69 : struct platform_device *pdev;
70 : int ret;
71 :
72 5 : ret = platform_driver_register(&fake_platform_driver);
73 5 : KUNIT_ASSERT_EQ(test, ret, 0);
74 :
75 5 : ret = kunit_add_action_or_reset(test,
76 : kunit_action_platform_driver_unregister,
77 : &fake_platform_driver);
78 5 : KUNIT_ASSERT_EQ(test, ret, 0);
79 :
80 5 : pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
81 10 : KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
82 :
83 5 : ret = kunit_add_action_or_reset(test,
84 : kunit_action_platform_device_put,
85 : pdev);
86 5 : KUNIT_ASSERT_EQ(test, ret, 0);
87 :
88 5 : ret = platform_device_add(pdev);
89 5 : KUNIT_ASSERT_EQ(test, ret, 0);
90 :
91 5 : ret = kunit_add_action_or_reset(test,
92 : kunit_action_platform_device_del,
93 : pdev);
94 5 : KUNIT_ASSERT_EQ(test, ret, 0);
95 :
96 5 : return &pdev->dev;
97 : }
98 : EXPORT_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 : */
107 0 : void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
108 : {
109 0 : struct platform_device *pdev = to_platform_device(dev);
110 :
111 0 : kunit_release_action(test,
112 : kunit_action_platform_device_del,
113 : pdev);
114 :
115 0 : kunit_release_action(test,
116 : kunit_action_platform_device_put,
117 : pdev);
118 :
119 0 : kunit_release_action(test,
120 : kunit_action_platform_driver_unregister,
121 : pdev);
122 0 : }
123 : EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
124 :
125 : struct drm_device *
126 5 : __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 5 : container = __devm_drm_dev_alloc(dev, driver, size, offset);
136 5 : if (IS_ERR(container))
137 : return ERR_CAST(container);
138 :
139 5 : drm = container + offset;
140 5 : drm->mode_config.funcs = &drm_mode_config_funcs;
141 :
142 5 : ret = drmm_mode_config_init(drm);
143 5 : if (ret)
144 0 : return ERR_PTR(ret);
145 :
146 : return drm;
147 : }
148 : EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
149 :
150 0 : static void action_drm_release_context(void *ptr)
151 : {
152 0 : struct drm_modeset_acquire_ctx *ctx = ptr;
153 :
154 0 : drm_modeset_drop_locks(ctx);
155 0 : drm_modeset_acquire_fini(ctx);
156 0 : }
157 :
158 : /**
159 : * drm_kunit_helper_context_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 : */
170 : struct drm_modeset_acquire_ctx *
171 0 : drm_kunit_helper_acquire_ctx_alloc(struct kunit *test)
172 : {
173 : struct drm_modeset_acquire_ctx *ctx;
174 : int ret;
175 :
176 0 : ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
177 0 : KUNIT_ASSERT_NOT_NULL(test, ctx);
178 :
179 0 : drm_modeset_acquire_init(ctx, 0);
180 :
181 0 : ret = kunit_add_action_or_reset(test,
182 : action_drm_release_context,
183 : ctx);
184 0 : if (ret)
185 0 : return ERR_PTR(ret);
186 :
187 : return ctx;
188 : }
189 : EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
190 :
191 0 : static void kunit_action_drm_atomic_state_put(void *ptr)
192 : {
193 0 : struct drm_atomic_state *state = ptr;
194 :
195 0 : drm_atomic_state_put(state);
196 0 : }
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 : */
212 : struct drm_atomic_state *
213 0 : drm_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 0 : state = drm_atomic_state_alloc(drm);
221 0 : if (!state)
222 : return ERR_PTR(-ENOMEM);
223 :
224 0 : ret = kunit_add_action_or_reset(test,
225 : kunit_action_drm_atomic_state_put,
226 : state);
227 0 : if (ret)
228 0 : return ERR_PTR(ret);
229 :
230 0 : state->acquire_ctx = ctx;
231 :
232 0 : return state;
233 : }
234 : EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
235 :
236 : MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
237 : MODULE_LICENSE("GPL");
|