summaryrefslogtreecommitdiff
path: root/drivers/staging/greybus/svc.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@hovoldconsulting.com>2016-05-27 17:26:40 +0200
committerGreg Kroah-Hartman <gregkh@google.com>2016-05-27 12:24:17 -0700
commit55742d2a071a569bf20f90d37b1b5b8a25a3f882 (patch)
tree7438d9c12c2ec57706973a7eb9a80bc44b897edb /drivers/staging/greybus/svc.c
parent08f94352e8d09f7db07b4e894b3c223ee92df5ad (diff)
greybus: interface: implement generic mode-switch functionality
Add a generic interface for bundle drivers to use to request that a mode switch is carried out on its behalf. Mode switching involves tearing down all connections to an interface, sending a unidirectional mode-switch request, and waiting for a mailbox event that triggers deferred control connection reset and re-enumeration of the interface. In case of a timeout waiting for the interface mailbox event, or on other errors, the interface is powered off. All of this needs to be done by core from work-queue context in order not to block incoming SVC requests and bundle-device tear down. Care must also be taken to serialise against concurrent module removal events and eject requests. Special handling of legacy mode-switching is also added in order to continue to support the ES3 bootrom. Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/svc.c')
-rw-r--r--drivers/staging/greybus/svc.c55
1 files changed, 4 insertions, 51 deletions
diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c
index 4176e231b14a..9df3f570eb83 100644
--- a/drivers/staging/greybus/svc.c
+++ b/drivers/staging/greybus/svc.c
@@ -895,28 +895,6 @@ static struct gb_module *gb_svc_module_lookup(struct gb_svc *svc, u8 module_id)
return NULL;
}
-static void gb_svc_intf_reenable(struct gb_svc *svc, struct gb_interface *intf)
-{
- int ret;
-
- mutex_lock(&intf->mutex);
-
- /* Mark as disconnected to prevent I/O during disable. */
- intf->disconnected = true;
- gb_interface_disable(intf);
- intf->disconnected = false;
-
- ret = gb_interface_enable(intf);
- if (ret) {
- dev_err(&svc->dev, "failed to enable interface %u: %d\n",
- intf->interface_id, ret);
-
- gb_interface_deactivate(intf);
- }
-
- mutex_unlock(&intf->mutex);
-}
-
static void gb_svc_process_hello_deferred(struct gb_operation *operation)
{
struct gb_connection *connection = operation->connection;
@@ -965,10 +943,9 @@ static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
/* All modules are considered 1x2 for now */
module = gb_svc_module_lookup(svc, intf_id);
if (module) {
- dev_info(&svc->dev, "mode switch detected on interface %u\n",
- intf_id);
-
- return gb_svc_intf_reenable(svc, module->interfaces[0]);
+ /* legacy mode switch */
+ return gb_interface_mailbox_event(module->interfaces[0], 0,
+ GB_SVC_INTF_MAILBOX_GREYBUS);
}
module = gb_module_create(hd, intf_id, 1);
@@ -1115,31 +1092,7 @@ static void gb_svc_process_intf_mailbox_event(struct gb_operation *operation)
return;
}
- if (result_code) {
- dev_warn(&svc->dev,
- "mailbox event %u with UniPro error: 0x%04x\n",
- intf_id, result_code);
- goto err_disable_interface;
- }
-
- if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) {
- dev_warn(&svc->dev,
- "mailbox event %u with unexected value: 0x%08x\n",
- intf_id, mailbox);
- goto err_disable_interface;
- }
-
- dev_info(&svc->dev, "mode switch detected on interface %u\n", intf_id);
-
- gb_svc_intf_reenable(svc, intf);
-
- return;
-
-err_disable_interface:
- mutex_lock(&intf->mutex);
- gb_interface_disable(intf);
- gb_interface_deactivate(intf);
- mutex_unlock(&intf->mutex);
+ gb_interface_mailbox_event(intf, result_code, mailbox);
}
static void gb_svc_process_deferred_request(struct work_struct *work)