Merge tag 'powerpc-6.6-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / tests / drm_kunit_helpers.c
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 static void kunit_action_platform_driver_unregister(void *ptr)
31 {
32         struct platform_driver *drv = ptr;
33
34         platform_driver_unregister(drv);
35
36 }
37
38 static void kunit_action_platform_device_put(void *ptr)
39 {
40         struct platform_device *pdev = ptr;
41
42         platform_device_put(pdev);
43 }
44
45 static 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  */
67 struct 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 }
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 void 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 }
123 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
124
125 struct 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 }
148 EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
149
150 static 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  */
170 struct drm_modeset_acquire_ctx *
171 drm_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 }
189 EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
190
191 static 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  */
212 struct drm_atomic_state *
213 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         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 }
234 EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
235
236 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
237 MODULE_LICENSE("GPL");