xref: /linux/drivers/greybus/core.c (revision 71dfa617ea9f18e4585fe78364217cd32b1fc382)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Greybus "Core"
4  *
5  * Copyright 2014-2015 Google Inc.
6  * Copyright 2014-2015 Linaro Ltd.
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #define CREATE_TRACE_POINTS
12 #include <linux/greybus.h>
13 #include "greybus_trace.h"
14 
15 #define GB_BUNDLE_AUTOSUSPEND_MS	3000
16 
17 /* Allow greybus to be disabled at boot if needed */
18 static bool nogreybus;
19 #ifdef MODULE
20 module_param(nogreybus, bool, 0444);
21 #else
22 core_param(nogreybus, nogreybus, bool, 0444);
23 #endif
24 int greybus_disabled(void)
25 {
26 	return nogreybus;
27 }
28 EXPORT_SYMBOL_GPL(greybus_disabled);
29 
30 static int is_gb_host_device(const struct device *dev)
31 {
32 	return dev->type == &greybus_hd_type;
33 }
34 
35 static int is_gb_module(const struct device *dev)
36 {
37 	return dev->type == &greybus_module_type;
38 }
39 
40 static int is_gb_interface(const struct device *dev)
41 {
42 	return dev->type == &greybus_interface_type;
43 }
44 
45 static int is_gb_control(const struct device *dev)
46 {
47 	return dev->type == &greybus_control_type;
48 }
49 
50 static int is_gb_bundle(const struct device *dev)
51 {
52 	return dev->type == &greybus_bundle_type;
53 }
54 
55 static int is_gb_svc(const struct device *dev)
56 {
57 	return dev->type == &greybus_svc_type;
58 }
59 
60 static bool greybus_match_one_id(struct gb_bundle *bundle,
61 				 const struct greybus_bundle_id *id)
62 {
63 	if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
64 	    (id->vendor != bundle->intf->vendor_id))
65 		return false;
66 
67 	if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
68 	    (id->product != bundle->intf->product_id))
69 		return false;
70 
71 	if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
72 	    (id->class != bundle->class))
73 		return false;
74 
75 	return true;
76 }
77 
78 static const struct greybus_bundle_id *
79 greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
80 {
81 	if (!id)
82 		return NULL;
83 
84 	for (; id->vendor || id->product || id->class || id->driver_info;
85 									id++) {
86 		if (greybus_match_one_id(bundle, id))
87 			return id;
88 	}
89 
90 	return NULL;
91 }
92 
93 static int greybus_match_device(struct device *dev, struct device_driver *drv)
94 {
95 	struct greybus_driver *driver = to_greybus_driver(drv);
96 	struct gb_bundle *bundle;
97 	const struct greybus_bundle_id *id;
98 
99 	if (!is_gb_bundle(dev))
100 		return 0;
101 
102 	bundle = to_gb_bundle(dev);
103 
104 	id = greybus_match_id(bundle, driver->id_table);
105 	if (id)
106 		return 1;
107 	/* FIXME - Dynamic ids? */
108 	return 0;
109 }
110 
111 static int greybus_uevent(const struct device *dev, struct kobj_uevent_env *env)
112 {
113 	const struct gb_host_device *hd;
114 	const struct gb_module *module = NULL;
115 	const struct gb_interface *intf = NULL;
116 	const struct gb_control *control = NULL;
117 	const struct gb_bundle *bundle = NULL;
118 	const struct gb_svc *svc = NULL;
119 
120 	if (is_gb_host_device(dev)) {
121 		hd = to_gb_host_device(dev);
122 	} else if (is_gb_module(dev)) {
123 		module = to_gb_module(dev);
124 		hd = module->hd;
125 	} else if (is_gb_interface(dev)) {
126 		intf = to_gb_interface(dev);
127 		module = intf->module;
128 		hd = intf->hd;
129 	} else if (is_gb_control(dev)) {
130 		control = to_gb_control(dev);
131 		intf = control->intf;
132 		module = intf->module;
133 		hd = intf->hd;
134 	} else if (is_gb_bundle(dev)) {
135 		bundle = to_gb_bundle(dev);
136 		intf = bundle->intf;
137 		module = intf->module;
138 		hd = intf->hd;
139 	} else if (is_gb_svc(dev)) {
140 		svc = to_gb_svc(dev);
141 		hd = svc->hd;
142 	} else {
143 		dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
144 		return -EINVAL;
145 	}
146 
147 	if (add_uevent_var(env, "BUS=%u", hd->bus_id))
148 		return -ENOMEM;
149 
150 	if (module) {
151 		if (add_uevent_var(env, "MODULE=%u", module->module_id))
152 			return -ENOMEM;
153 	}
154 
155 	if (intf) {
156 		if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
157 			return -ENOMEM;
158 		if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
159 				   intf->vendor_id, intf->product_id))
160 			return -ENOMEM;
161 	}
162 
163 	if (bundle) {
164 		// FIXME
165 		// add a uevent that can "load" a bundle type
166 		// This is what we need to bind a driver to so use the info
167 		// in gmod here as well
168 
169 		if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
170 			return -ENOMEM;
171 		if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
172 			return -ENOMEM;
173 	}
174 
175 	return 0;
176 }
177 
178 static void greybus_shutdown(struct device *dev)
179 {
180 	if (is_gb_host_device(dev)) {
181 		struct gb_host_device *hd;
182 
183 		hd = to_gb_host_device(dev);
184 		gb_hd_shutdown(hd);
185 	}
186 }
187 
188 const struct bus_type greybus_bus_type = {
189 	.name =		"greybus",
190 	.match =	greybus_match_device,
191 	.uevent =	greybus_uevent,
192 	.shutdown =	greybus_shutdown,
193 };
194 
195 static int greybus_probe(struct device *dev)
196 {
197 	struct greybus_driver *driver = to_greybus_driver(dev->driver);
198 	struct gb_bundle *bundle = to_gb_bundle(dev);
199 	const struct greybus_bundle_id *id;
200 	int retval;
201 
202 	/* match id */
203 	id = greybus_match_id(bundle, driver->id_table);
204 	if (!id)
205 		return -ENODEV;
206 
207 	retval = pm_runtime_get_sync(&bundle->intf->dev);
208 	if (retval < 0) {
209 		pm_runtime_put_noidle(&bundle->intf->dev);
210 		return retval;
211 	}
212 
213 	retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
214 	if (retval) {
215 		pm_runtime_put(&bundle->intf->dev);
216 		return retval;
217 	}
218 
219 	/*
220 	 * Unbound bundle devices are always deactivated. During probe, the
221 	 * Runtime PM is set to enabled and active and the usage count is
222 	 * incremented. If the driver supports runtime PM, it should call
223 	 * pm_runtime_put() in its probe routine and pm_runtime_get_sync()
224 	 * in remove routine.
225 	 */
226 	pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
227 	pm_runtime_use_autosuspend(dev);
228 	pm_runtime_get_noresume(dev);
229 	pm_runtime_set_active(dev);
230 	pm_runtime_enable(dev);
231 
232 	retval = driver->probe(bundle, id);
233 	if (retval) {
234 		/*
235 		 * Catch buggy drivers that fail to destroy their connections.
236 		 */
237 		WARN_ON(!list_empty(&bundle->connections));
238 
239 		gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
240 
241 		pm_runtime_disable(dev);
242 		pm_runtime_set_suspended(dev);
243 		pm_runtime_put_noidle(dev);
244 		pm_runtime_dont_use_autosuspend(dev);
245 		pm_runtime_put(&bundle->intf->dev);
246 
247 		return retval;
248 	}
249 
250 	pm_runtime_put(&bundle->intf->dev);
251 
252 	return 0;
253 }
254 
255 static int greybus_remove(struct device *dev)
256 {
257 	struct greybus_driver *driver = to_greybus_driver(dev->driver);
258 	struct gb_bundle *bundle = to_gb_bundle(dev);
259 	struct gb_connection *connection;
260 	int retval;
261 
262 	retval = pm_runtime_get_sync(dev);
263 	if (retval < 0)
264 		dev_err(dev, "failed to resume bundle: %d\n", retval);
265 
266 	/*
267 	 * Disable (non-offloaded) connections early in case the interface is
268 	 * already gone to avoid unceccessary operation timeouts during
269 	 * driver disconnect. Otherwise, only disable incoming requests.
270 	 */
271 	list_for_each_entry(connection, &bundle->connections, bundle_links) {
272 		if (gb_connection_is_offloaded(connection))
273 			continue;
274 
275 		if (bundle->intf->disconnected)
276 			gb_connection_disable_forced(connection);
277 		else
278 			gb_connection_disable_rx(connection);
279 	}
280 
281 	driver->disconnect(bundle);
282 
283 	/* Catch buggy drivers that fail to destroy their connections. */
284 	WARN_ON(!list_empty(&bundle->connections));
285 
286 	if (!bundle->intf->disconnected)
287 		gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
288 
289 	pm_runtime_put_noidle(dev);
290 	pm_runtime_disable(dev);
291 	pm_runtime_set_suspended(dev);
292 	pm_runtime_dont_use_autosuspend(dev);
293 	pm_runtime_put_noidle(dev);
294 
295 	return 0;
296 }
297 
298 int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
299 			    const char *mod_name)
300 {
301 	int retval;
302 
303 	if (greybus_disabled())
304 		return -ENODEV;
305 
306 	driver->driver.bus = &greybus_bus_type;
307 	driver->driver.name = driver->name;
308 	driver->driver.probe = greybus_probe;
309 	driver->driver.remove = greybus_remove;
310 	driver->driver.owner = owner;
311 	driver->driver.mod_name = mod_name;
312 
313 	retval = driver_register(&driver->driver);
314 	if (retval)
315 		return retval;
316 
317 	pr_info("registered new driver %s\n", driver->name);
318 	return 0;
319 }
320 EXPORT_SYMBOL_GPL(greybus_register_driver);
321 
322 void greybus_deregister_driver(struct greybus_driver *driver)
323 {
324 	driver_unregister(&driver->driver);
325 }
326 EXPORT_SYMBOL_GPL(greybus_deregister_driver);
327 
328 static int __init gb_init(void)
329 {
330 	int retval;
331 
332 	if (greybus_disabled())
333 		return -ENODEV;
334 
335 	BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
336 
337 	gb_debugfs_init();
338 
339 	retval = bus_register(&greybus_bus_type);
340 	if (retval) {
341 		pr_err("bus_register failed (%d)\n", retval);
342 		goto error_bus;
343 	}
344 
345 	retval = gb_hd_init();
346 	if (retval) {
347 		pr_err("gb_hd_init failed (%d)\n", retval);
348 		goto error_hd;
349 	}
350 
351 	retval = gb_operation_init();
352 	if (retval) {
353 		pr_err("gb_operation_init failed (%d)\n", retval);
354 		goto error_operation;
355 	}
356 	return 0;	/* Success */
357 
358 error_operation:
359 	gb_hd_exit();
360 error_hd:
361 	bus_unregister(&greybus_bus_type);
362 error_bus:
363 	gb_debugfs_cleanup();
364 
365 	return retval;
366 }
367 module_init(gb_init);
368 
369 static void __exit gb_exit(void)
370 {
371 	gb_operation_exit();
372 	gb_hd_exit();
373 	bus_unregister(&greybus_bus_type);
374 	gb_debugfs_cleanup();
375 	tracepoint_synchronize_unregister();
376 }
377 module_exit(gb_exit);
378 MODULE_LICENSE("GPL v2");
379 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
380