root/drivers/greybus/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. greybus_disabled
  2. greybus_match_one_id
  3. greybus_match_id
  4. greybus_match_device
  5. greybus_uevent
  6. greybus_shutdown
  7. greybus_probe
  8. greybus_remove
  9. greybus_register_driver
  10. greybus_deregister_driver
  11. gb_init
  12. gb_exit

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

/* [<][>][^][v][top][bottom][index][help] */