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