1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * KUnit-managed device implementation |
4 | * |
5 | * Implementation of struct kunit_device helpers for fake devices whose |
6 | * lifecycle is managed by KUnit. |
7 | * |
8 | * Copyright (C) 2023, Google LLC. |
9 | * Author: David Gow <davidgow@google.com> |
10 | */ |
11 | |
12 | #include <linux/device.h> |
13 | #include <linux/dma-mapping.h> |
14 | |
15 | #include <kunit/test.h> |
16 | #include <kunit/device.h> |
17 | #include <kunit/resource.h> |
18 | |
19 | #include "device-impl.h" |
20 | |
21 | /* Wrappers for use with kunit_add_action() */ |
22 | KUNIT_DEFINE_ACTION_WRAPPER(device_unregister_wrapper, device_unregister, struct device *); |
23 | KUNIT_DEFINE_ACTION_WRAPPER(driver_unregister_wrapper, driver_unregister, struct device_driver *); |
24 | |
25 | /* The root device for the KUnit bus, parent of all kunit_devices. */ |
26 | static struct device *kunit_bus_device; |
27 | |
28 | /* A device owned by a KUnit test. */ |
29 | struct kunit_device { |
30 | struct device dev; |
31 | /* The KUnit test which owns this device. */ |
32 | struct kunit *owner; |
33 | /* If the driver is managed by KUnit and unique to this device. */ |
34 | const struct device_driver *driver; |
35 | }; |
36 | |
37 | #define to_kunit_device(d) container_of_const(d, struct kunit_device, dev) |
38 | |
39 | static const struct bus_type kunit_bus_type = { |
40 | .name = "kunit" , |
41 | }; |
42 | |
43 | /* Register the 'kunit_bus' used for fake devices. */ |
44 | int kunit_bus_init(void) |
45 | { |
46 | int error; |
47 | |
48 | kunit_bus_device = root_device_register("kunit" ); |
49 | if (IS_ERR(ptr: kunit_bus_device)) |
50 | return PTR_ERR(ptr: kunit_bus_device); |
51 | |
52 | error = bus_register(bus: &kunit_bus_type); |
53 | if (error) |
54 | bus_unregister(bus: &kunit_bus_type); |
55 | return error; |
56 | } |
57 | |
58 | /* Unregister the 'kunit_bus' in case the KUnit module is unloaded. */ |
59 | void kunit_bus_shutdown(void) |
60 | { |
61 | /* Make sure the bus exists before we unregister it. */ |
62 | if (IS_ERR_OR_NULL(ptr: kunit_bus_device)) |
63 | return; |
64 | |
65 | bus_unregister(bus: &kunit_bus_type); |
66 | |
67 | root_device_unregister(root: kunit_bus_device); |
68 | |
69 | kunit_bus_device = NULL; |
70 | } |
71 | |
72 | /* Release a 'fake' KUnit device. */ |
73 | static void kunit_device_release(struct device *d) |
74 | { |
75 | kfree(to_kunit_device(d)); |
76 | } |
77 | |
78 | /* |
79 | * Create and register a KUnit-managed struct device_driver on the kunit_bus. |
80 | * Returns an error pointer on failure. |
81 | */ |
82 | struct device_driver *kunit_driver_create(struct kunit *test, const char *name) |
83 | { |
84 | struct device_driver *driver; |
85 | int err = -ENOMEM; |
86 | |
87 | driver = kunit_kzalloc(test, size: sizeof(*driver), GFP_KERNEL); |
88 | |
89 | if (!driver) |
90 | return ERR_PTR(error: err); |
91 | |
92 | driver->name = name; |
93 | driver->bus = &kunit_bus_type; |
94 | driver->owner = THIS_MODULE; |
95 | |
96 | err = driver_register(drv: driver); |
97 | if (err) { |
98 | kunit_kfree(test, ptr: driver); |
99 | return ERR_PTR(error: err); |
100 | } |
101 | |
102 | kunit_add_action(test, action: driver_unregister_wrapper, ctx: driver); |
103 | return driver; |
104 | } |
105 | EXPORT_SYMBOL_GPL(kunit_driver_create); |
106 | |
107 | /* Helper which creates a kunit_device, attaches it to the kunit_bus*/ |
108 | static struct kunit_device *kunit_device_register_internal(struct kunit *test, |
109 | const char *name, |
110 | const struct device_driver *drv) |
111 | { |
112 | struct kunit_device *kunit_dev; |
113 | int err = -ENOMEM; |
114 | |
115 | kunit_dev = kzalloc(size: sizeof(*kunit_dev), GFP_KERNEL); |
116 | if (!kunit_dev) |
117 | return ERR_PTR(error: err); |
118 | |
119 | kunit_dev->owner = test; |
120 | |
121 | err = dev_set_name(dev: &kunit_dev->dev, name: "%s.%s" , test->name, name); |
122 | if (err) { |
123 | kfree(objp: kunit_dev); |
124 | return ERR_PTR(error: err); |
125 | } |
126 | |
127 | kunit_dev->dev.release = kunit_device_release; |
128 | kunit_dev->dev.bus = &kunit_bus_type; |
129 | kunit_dev->dev.parent = kunit_bus_device; |
130 | |
131 | err = device_register(dev: &kunit_dev->dev); |
132 | if (err) { |
133 | put_device(dev: &kunit_dev->dev); |
134 | return ERR_PTR(error: err); |
135 | } |
136 | |
137 | kunit_dev->dev.dma_mask = &kunit_dev->dev.coherent_dma_mask; |
138 | kunit_dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
139 | |
140 | kunit_add_action(test, action: device_unregister_wrapper, ctx: &kunit_dev->dev); |
141 | |
142 | return kunit_dev; |
143 | } |
144 | |
145 | /* |
146 | * Create and register a new KUnit-managed device, using the user-supplied device_driver. |
147 | * On failure, returns an error pointer. |
148 | */ |
149 | struct device *kunit_device_register_with_driver(struct kunit *test, |
150 | const char *name, |
151 | const struct device_driver *drv) |
152 | { |
153 | struct kunit_device *kunit_dev = kunit_device_register_internal(test, name, drv); |
154 | |
155 | if (IS_ERR_OR_NULL(ptr: kunit_dev)) |
156 | return ERR_CAST(ptr: kunit_dev); |
157 | |
158 | return &kunit_dev->dev; |
159 | } |
160 | EXPORT_SYMBOL_GPL(kunit_device_register_with_driver); |
161 | |
162 | /* |
163 | * Create and register a new KUnit-managed device, including a matching device_driver. |
164 | * On failure, returns an error pointer. |
165 | */ |
166 | struct device *kunit_device_register(struct kunit *test, const char *name) |
167 | { |
168 | struct device_driver *drv; |
169 | struct kunit_device *dev; |
170 | |
171 | drv = kunit_driver_create(test, name); |
172 | if (IS_ERR(ptr: drv)) |
173 | return ERR_CAST(ptr: drv); |
174 | |
175 | dev = kunit_device_register_internal(test, name, drv); |
176 | if (IS_ERR(ptr: dev)) { |
177 | kunit_release_action(test, action: driver_unregister_wrapper, ctx: (void *)drv); |
178 | return ERR_CAST(ptr: dev); |
179 | } |
180 | |
181 | /* Request the driver be freed. */ |
182 | dev->driver = drv; |
183 | |
184 | |
185 | return &dev->dev; |
186 | } |
187 | EXPORT_SYMBOL_GPL(kunit_device_register); |
188 | |
189 | /* Unregisters a KUnit-managed device early (including the driver, if automatically created). */ |
190 | void kunit_device_unregister(struct kunit *test, struct device *dev) |
191 | { |
192 | const struct device_driver *driver = to_kunit_device(dev)->driver; |
193 | |
194 | kunit_release_action(test, action: device_unregister_wrapper, ctx: dev); |
195 | if (driver) |
196 | kunit_release_action(test, action: driver_unregister_wrapper, ctx: (void *)driver); |
197 | } |
198 | EXPORT_SYMBOL_GPL(kunit_device_unregister); |
199 | |
200 | |