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