|  | /* | 
|  | * Greybus Module code | 
|  | * | 
|  | * Copyright 2016 Google Inc. | 
|  | * Copyright 2016 Linaro Ltd. | 
|  | * | 
|  | * Released under the GPLv2 only. | 
|  | */ | 
|  |  | 
|  | #include "greybus.h" | 
|  |  | 
|  |  | 
|  | static ssize_t eject_store(struct device *dev, | 
|  | struct device_attribute *attr, | 
|  | const char *buf, size_t len) | 
|  | { | 
|  | struct gb_module *module = to_gb_module(dev); | 
|  | struct gb_interface *intf; | 
|  | size_t i; | 
|  | long val; | 
|  | int ret; | 
|  |  | 
|  | ret = kstrtol(buf, 0, &val); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | if (!val) | 
|  | return len; | 
|  |  | 
|  | for (i = 0; i < module->num_interfaces; ++i) { | 
|  | intf = module->interfaces[i]; | 
|  |  | 
|  | mutex_lock(&intf->mutex); | 
|  | /* Set flag to prevent concurrent activation. */ | 
|  | intf->ejected = true; | 
|  | gb_interface_disable(intf); | 
|  | gb_interface_deactivate(intf); | 
|  | mutex_unlock(&intf->mutex); | 
|  | } | 
|  |  | 
|  | /* Tell the SVC to eject the primary interface. */ | 
|  | ret = gb_svc_intf_eject(module->hd->svc, module->module_id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | return len; | 
|  | } | 
|  | static DEVICE_ATTR_WO(eject); | 
|  |  | 
|  | static ssize_t module_id_show(struct device *dev, | 
|  | struct device_attribute *attr, char *buf) | 
|  | { | 
|  | struct gb_module *module = to_gb_module(dev); | 
|  |  | 
|  | return sprintf(buf, "%u\n", module->module_id); | 
|  | } | 
|  | static DEVICE_ATTR_RO(module_id); | 
|  |  | 
|  | static ssize_t num_interfaces_show(struct device *dev, | 
|  | struct device_attribute *attr, char *buf) | 
|  | { | 
|  | struct gb_module *module = to_gb_module(dev); | 
|  |  | 
|  | return sprintf(buf, "%zu\n", module->num_interfaces); | 
|  | } | 
|  | static DEVICE_ATTR_RO(num_interfaces); | 
|  |  | 
|  | static struct attribute *module_attrs[] = { | 
|  | &dev_attr_eject.attr, | 
|  | &dev_attr_module_id.attr, | 
|  | &dev_attr_num_interfaces.attr, | 
|  | NULL, | 
|  | }; | 
|  | ATTRIBUTE_GROUPS(module); | 
|  |  | 
|  | static void gb_module_release(struct device *dev) | 
|  | { | 
|  | struct gb_module *module = to_gb_module(dev); | 
|  |  | 
|  | kfree(module); | 
|  | } | 
|  |  | 
|  | struct device_type greybus_module_type = { | 
|  | .name		= "greybus_module", | 
|  | .release	= gb_module_release, | 
|  | }; | 
|  |  | 
|  | struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id, | 
|  | size_t num_interfaces) | 
|  | { | 
|  | struct gb_interface *intf; | 
|  | struct gb_module *module; | 
|  | int i; | 
|  |  | 
|  | module = kzalloc(sizeof(*module) + num_interfaces * sizeof(intf), | 
|  | GFP_KERNEL); | 
|  | if (!module) | 
|  | return NULL; | 
|  |  | 
|  | module->hd = hd; | 
|  | module->module_id = module_id; | 
|  | module->num_interfaces = num_interfaces; | 
|  |  | 
|  | module->dev.parent = &hd->dev; | 
|  | module->dev.bus = &greybus_bus_type; | 
|  | module->dev.type = &greybus_module_type; | 
|  | module->dev.groups = module_groups; | 
|  | module->dev.dma_mask = hd->dev.dma_mask; | 
|  | device_initialize(&module->dev); | 
|  | dev_set_name(&module->dev, "%d-%u", hd->bus_id, module_id); | 
|  |  | 
|  | for (i = 0; i < num_interfaces; ++i) { | 
|  | intf = gb_interface_create(module, module_id + i); | 
|  | if (!intf) { | 
|  | dev_err(&module->dev, "failed to create interface %u\n", | 
|  | module_id + i); | 
|  | goto err_put_interfaces; | 
|  | } | 
|  | module->interfaces[i] = intf; | 
|  | } | 
|  |  | 
|  | return module; | 
|  |  | 
|  | err_put_interfaces: | 
|  | for (--i; i > 0; --i) | 
|  | gb_interface_put(module->interfaces[i]); | 
|  |  | 
|  | put_device(&module->dev); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Register and enable an interface after first attempting to activate it. | 
|  | */ | 
|  | static void gb_module_register_interface(struct gb_interface *intf) | 
|  | { | 
|  | struct gb_module *module = intf->module; | 
|  | u8 intf_id = intf->interface_id; | 
|  | int ret; | 
|  | int retries = 3; | 
|  |  | 
|  | mutex_lock(&intf->mutex); | 
|  |  | 
|  | while (retries--) { | 
|  | ret = gb_interface_activate(intf); | 
|  | if (ret != -EAGAIN) | 
|  | break; | 
|  | } | 
|  | if (ret) { | 
|  | dev_err(&module->dev, "failed to activate interface %u: %d\n", | 
|  | intf_id, ret); | 
|  |  | 
|  | /* | 
|  | * -EAGAIN indicates that the Greybus operation | 
|  | * interface_activate determined the remote interface to be | 
|  | * UniPro-only.  At present, we assume a UniPro-only module | 
|  | * to be a Greybus module that failed to send its mailbox | 
|  | * poke.  There is some reason to believe that this is | 
|  | * because of a bug in the ES3 bootrom.  If we exhause our | 
|  | * retries trying to activate such an interface, convert | 
|  | * the error code back into a "no device" error. | 
|  | */ | 
|  | if (ret == -EAGAIN) | 
|  | ret = -ENODEV; | 
|  |  | 
|  | gb_interface_add(intf); | 
|  | goto err_unlock; | 
|  | } | 
|  |  | 
|  | ret = gb_interface_add(intf); | 
|  | if (ret) | 
|  | goto err_interface_deactivate; | 
|  |  | 
|  | ret = gb_interface_enable(intf); | 
|  | if (ret) { | 
|  | dev_err(&module->dev, "failed to enable interface %u: %d\n", | 
|  | intf_id, ret); | 
|  | goto err_interface_deactivate; | 
|  | } | 
|  |  | 
|  | mutex_unlock(&intf->mutex); | 
|  |  | 
|  | return; | 
|  |  | 
|  | err_interface_deactivate: | 
|  | gb_interface_deactivate(intf); | 
|  | err_unlock: | 
|  | mutex_unlock(&intf->mutex); | 
|  | } | 
|  |  | 
|  | static void gb_module_deregister_interface(struct gb_interface *intf) | 
|  | { | 
|  | /* Mark as disconnected to prevent I/O during disable. */ | 
|  | if (intf->module->disconnected) | 
|  | intf->disconnected = true; | 
|  |  | 
|  | mutex_lock(&intf->mutex); | 
|  | gb_interface_disable(intf); | 
|  | gb_interface_deactivate(intf); | 
|  | mutex_unlock(&intf->mutex); | 
|  |  | 
|  | gb_interface_del(intf); | 
|  | } | 
|  |  | 
|  | /* Register a module and its interfaces. */ | 
|  | int gb_module_add(struct gb_module *module) | 
|  | { | 
|  | size_t i; | 
|  | int ret; | 
|  |  | 
|  | ret = device_add(&module->dev); | 
|  | if (ret) { | 
|  | dev_err(&module->dev, "failed to register module: %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < module->num_interfaces; ++i) | 
|  | gb_module_register_interface(module->interfaces[i]); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Deregister a module and its interfaces. */ | 
|  | void gb_module_del(struct gb_module *module) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < module->num_interfaces; ++i) | 
|  | gb_module_deregister_interface(module->interfaces[i]); | 
|  |  | 
|  | device_del(&module->dev); | 
|  | } | 
|  |  | 
|  | void gb_module_put(struct gb_module *module) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < module->num_interfaces; ++i) | 
|  | gb_interface_put(module->interfaces[i]); | 
|  |  | 
|  | put_device(&module->dev); | 
|  | } |