Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus "Core"
0004  *
0005  * Copyright 2014-2015 Google Inc.
0006  * Copyright 2014-2015 Linaro Ltd.
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #define CREATE_TRACE_POINTS
0012 #include <linux/greybus.h>
0013 #include "greybus_trace.h"
0014 
0015 #define GB_BUNDLE_AUTOSUSPEND_MS    3000
0016 
0017 /* Allow greybus to be disabled at boot if needed */
0018 static bool nogreybus;
0019 #ifdef MODULE
0020 module_param(nogreybus, bool, 0444);
0021 #else
0022 core_param(nogreybus, nogreybus, bool, 0444);
0023 #endif
0024 int greybus_disabled(void)
0025 {
0026     return nogreybus;
0027 }
0028 EXPORT_SYMBOL_GPL(greybus_disabled);
0029 
0030 static bool greybus_match_one_id(struct gb_bundle *bundle,
0031                  const struct greybus_bundle_id *id)
0032 {
0033     if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
0034         (id->vendor != bundle->intf->vendor_id))
0035         return false;
0036 
0037     if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
0038         (id->product != bundle->intf->product_id))
0039         return false;
0040 
0041     if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
0042         (id->class != bundle->class))
0043         return false;
0044 
0045     return true;
0046 }
0047 
0048 static const struct greybus_bundle_id *
0049 greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
0050 {
0051     if (!id)
0052         return NULL;
0053 
0054     for (; id->vendor || id->product || id->class || id->driver_info;
0055                                     id++) {
0056         if (greybus_match_one_id(bundle, id))
0057             return id;
0058     }
0059 
0060     return NULL;
0061 }
0062 
0063 static int greybus_match_device(struct device *dev, struct device_driver *drv)
0064 {
0065     struct greybus_driver *driver = to_greybus_driver(drv);
0066     struct gb_bundle *bundle;
0067     const struct greybus_bundle_id *id;
0068 
0069     if (!is_gb_bundle(dev))
0070         return 0;
0071 
0072     bundle = to_gb_bundle(dev);
0073 
0074     id = greybus_match_id(bundle, driver->id_table);
0075     if (id)
0076         return 1;
0077     /* FIXME - Dynamic ids? */
0078     return 0;
0079 }
0080 
0081 static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
0082 {
0083     struct gb_host_device *hd;
0084     struct gb_module *module = NULL;
0085     struct gb_interface *intf = NULL;
0086     struct gb_control *control = NULL;
0087     struct gb_bundle *bundle = NULL;
0088     struct gb_svc *svc = NULL;
0089 
0090     if (is_gb_host_device(dev)) {
0091         hd = to_gb_host_device(dev);
0092     } else if (is_gb_module(dev)) {
0093         module = to_gb_module(dev);
0094         hd = module->hd;
0095     } else if (is_gb_interface(dev)) {
0096         intf = to_gb_interface(dev);
0097         module = intf->module;
0098         hd = intf->hd;
0099     } else if (is_gb_control(dev)) {
0100         control = to_gb_control(dev);
0101         intf = control->intf;
0102         module = intf->module;
0103         hd = intf->hd;
0104     } else if (is_gb_bundle(dev)) {
0105         bundle = to_gb_bundle(dev);
0106         intf = bundle->intf;
0107         module = intf->module;
0108         hd = intf->hd;
0109     } else if (is_gb_svc(dev)) {
0110         svc = to_gb_svc(dev);
0111         hd = svc->hd;
0112     } else {
0113         dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
0114         return -EINVAL;
0115     }
0116 
0117     if (add_uevent_var(env, "BUS=%u", hd->bus_id))
0118         return -ENOMEM;
0119 
0120     if (module) {
0121         if (add_uevent_var(env, "MODULE=%u", module->module_id))
0122             return -ENOMEM;
0123     }
0124 
0125     if (intf) {
0126         if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
0127             return -ENOMEM;
0128         if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
0129                    intf->vendor_id, intf->product_id))
0130             return -ENOMEM;
0131     }
0132 
0133     if (bundle) {
0134         // FIXME
0135         // add a uevent that can "load" a bundle type
0136         // This is what we need to bind a driver to so use the info
0137         // in gmod here as well
0138 
0139         if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
0140             return -ENOMEM;
0141         if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
0142             return -ENOMEM;
0143     }
0144 
0145     return 0;
0146 }
0147 
0148 static void greybus_shutdown(struct device *dev)
0149 {
0150     if (is_gb_host_device(dev)) {
0151         struct gb_host_device *hd;
0152 
0153         hd = to_gb_host_device(dev);
0154         gb_hd_shutdown(hd);
0155     }
0156 }
0157 
0158 struct bus_type greybus_bus_type = {
0159     .name =     "greybus",
0160     .match =    greybus_match_device,
0161     .uevent =   greybus_uevent,
0162     .shutdown = greybus_shutdown,
0163 };
0164 
0165 static int greybus_probe(struct device *dev)
0166 {
0167     struct greybus_driver *driver = to_greybus_driver(dev->driver);
0168     struct gb_bundle *bundle = to_gb_bundle(dev);
0169     const struct greybus_bundle_id *id;
0170     int retval;
0171 
0172     /* match id */
0173     id = greybus_match_id(bundle, driver->id_table);
0174     if (!id)
0175         return -ENODEV;
0176 
0177     retval = pm_runtime_get_sync(&bundle->intf->dev);
0178     if (retval < 0) {
0179         pm_runtime_put_noidle(&bundle->intf->dev);
0180         return retval;
0181     }
0182 
0183     retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
0184     if (retval) {
0185         pm_runtime_put(&bundle->intf->dev);
0186         return retval;
0187     }
0188 
0189     /*
0190      * Unbound bundle devices are always deactivated. During probe, the
0191      * Runtime PM is set to enabled and active and the usage count is
0192      * incremented. If the driver supports runtime PM, it should call
0193      * pm_runtime_put() in its probe routine and pm_runtime_get_sync()
0194      * in remove routine.
0195      */
0196     pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
0197     pm_runtime_use_autosuspend(dev);
0198     pm_runtime_get_noresume(dev);
0199     pm_runtime_set_active(dev);
0200     pm_runtime_enable(dev);
0201 
0202     retval = driver->probe(bundle, id);
0203     if (retval) {
0204         /*
0205          * Catch buggy drivers that fail to destroy their connections.
0206          */
0207         WARN_ON(!list_empty(&bundle->connections));
0208 
0209         gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
0210 
0211         pm_runtime_disable(dev);
0212         pm_runtime_set_suspended(dev);
0213         pm_runtime_put_noidle(dev);
0214         pm_runtime_dont_use_autosuspend(dev);
0215         pm_runtime_put(&bundle->intf->dev);
0216 
0217         return retval;
0218     }
0219 
0220     pm_runtime_put(&bundle->intf->dev);
0221 
0222     return 0;
0223 }
0224 
0225 static int greybus_remove(struct device *dev)
0226 {
0227     struct greybus_driver *driver = to_greybus_driver(dev->driver);
0228     struct gb_bundle *bundle = to_gb_bundle(dev);
0229     struct gb_connection *connection;
0230     int retval;
0231 
0232     retval = pm_runtime_get_sync(dev);
0233     if (retval < 0)
0234         dev_err(dev, "failed to resume bundle: %d\n", retval);
0235 
0236     /*
0237      * Disable (non-offloaded) connections early in case the interface is
0238      * already gone to avoid unceccessary operation timeouts during
0239      * driver disconnect. Otherwise, only disable incoming requests.
0240      */
0241     list_for_each_entry(connection, &bundle->connections, bundle_links) {
0242         if (gb_connection_is_offloaded(connection))
0243             continue;
0244 
0245         if (bundle->intf->disconnected)
0246             gb_connection_disable_forced(connection);
0247         else
0248             gb_connection_disable_rx(connection);
0249     }
0250 
0251     driver->disconnect(bundle);
0252 
0253     /* Catch buggy drivers that fail to destroy their connections. */
0254     WARN_ON(!list_empty(&bundle->connections));
0255 
0256     if (!bundle->intf->disconnected)
0257         gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
0258 
0259     pm_runtime_put_noidle(dev);
0260     pm_runtime_disable(dev);
0261     pm_runtime_set_suspended(dev);
0262     pm_runtime_dont_use_autosuspend(dev);
0263     pm_runtime_put_noidle(dev);
0264 
0265     return 0;
0266 }
0267 
0268 int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
0269                 const char *mod_name)
0270 {
0271     int retval;
0272 
0273     if (greybus_disabled())
0274         return -ENODEV;
0275 
0276     driver->driver.bus = &greybus_bus_type;
0277     driver->driver.name = driver->name;
0278     driver->driver.probe = greybus_probe;
0279     driver->driver.remove = greybus_remove;
0280     driver->driver.owner = owner;
0281     driver->driver.mod_name = mod_name;
0282 
0283     retval = driver_register(&driver->driver);
0284     if (retval)
0285         return retval;
0286 
0287     pr_info("registered new driver %s\n", driver->name);
0288     return 0;
0289 }
0290 EXPORT_SYMBOL_GPL(greybus_register_driver);
0291 
0292 void greybus_deregister_driver(struct greybus_driver *driver)
0293 {
0294     driver_unregister(&driver->driver);
0295 }
0296 EXPORT_SYMBOL_GPL(greybus_deregister_driver);
0297 
0298 static int __init gb_init(void)
0299 {
0300     int retval;
0301 
0302     if (greybus_disabled())
0303         return -ENODEV;
0304 
0305     BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
0306 
0307     gb_debugfs_init();
0308 
0309     retval = bus_register(&greybus_bus_type);
0310     if (retval) {
0311         pr_err("bus_register failed (%d)\n", retval);
0312         goto error_bus;
0313     }
0314 
0315     retval = gb_hd_init();
0316     if (retval) {
0317         pr_err("gb_hd_init failed (%d)\n", retval);
0318         goto error_hd;
0319     }
0320 
0321     retval = gb_operation_init();
0322     if (retval) {
0323         pr_err("gb_operation_init failed (%d)\n", retval);
0324         goto error_operation;
0325     }
0326     return 0;   /* Success */
0327 
0328 error_operation:
0329     gb_hd_exit();
0330 error_hd:
0331     bus_unregister(&greybus_bus_type);
0332 error_bus:
0333     gb_debugfs_cleanup();
0334 
0335     return retval;
0336 }
0337 module_init(gb_init);
0338 
0339 static void __exit gb_exit(void)
0340 {
0341     gb_operation_exit();
0342     gb_hd_exit();
0343     bus_unregister(&greybus_bus_type);
0344     gb_debugfs_cleanup();
0345     tracepoint_synchronize_unregister();
0346 }
0347 module_exit(gb_exit);
0348 MODULE_LICENSE("GPL v2");
0349 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");