diff options
author | Johan Hovold <johan@hovoldconsulting.com> | 2016-05-27 17:26:40 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2016-05-27 12:24:17 -0700 |
commit | 55742d2a071a569bf20f90d37b1b5b8a25a3f882 (patch) | |
tree | 7438d9c12c2ec57706973a7eb9a80bc44b897edb /drivers/staging/greybus/svc.c | |
parent | 08f94352e8d09f7db07b4e894b3c223ee92df5ad (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.c | 55 |
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) |