From: Johan Hovold Date: Wed, 9 Mar 2016 11:20:43 +0000 (+0100) Subject: greybus: interface: separate disabling from removal X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=629c0d007de962bb4edca7b959cebebb29746e90;p=linux-beck.git greybus: interface: separate disabling from removal Separate interface disable from interface removal. Disabling an interface means tearing down its control connection and destroying (i.e. deregistering and releasing) its bundles, while removing it means deregistering and releasing the interface itself. This is needed to implement controlled module removal, where the module interfaces are disabled before being physically ejected. Signed-off-by: Johan Hovold Reviewed-by: Jeffrey Carlyle Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index 072e7c5a72e6..44226c4c48ec 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -137,36 +137,6 @@ struct gb_interface *gb_interface_create(struct gb_host_device *hd, return intf; } -/* - * Tear down a previously set up interface. - */ -void gb_interface_remove(struct gb_interface *intf) -{ - struct gb_bundle *bundle; - struct gb_bundle *next; - - /* - * Disable the control-connection early to avoid operation timeouts - * when the interface is already gone. - */ - if (intf->disconnected) - gb_control_disable(intf->control); - - list_for_each_entry_safe(bundle, next, &intf->bundles, links) - gb_bundle_destroy(bundle); - - if (device_is_registered(&intf->dev)) { - device_del(&intf->dev); - dev_info(&intf->dev, "Interface removed\n"); - } - - gb_control_disable(intf->control); - - list_del(&intf->links); - - put_device(&intf->dev); -} - /* * Enable an interface by enabling its control connection and fetching the * manifest and other information over it. @@ -241,6 +211,25 @@ err_disable_control: return ret; } +/* Disable an interface and destroy its bundles. */ +void gb_interface_disable(struct gb_interface *intf) +{ + struct gb_bundle *bundle; + struct gb_bundle *next; + + /* + * Disable the control-connection early to avoid operation timeouts + * when the interface is already gone. + */ + if (intf->disconnected) + gb_control_disable(intf->control); + + list_for_each_entry_safe(bundle, next, &intf->bundles, links) + gb_bundle_destroy(bundle); + + gb_control_disable(intf->control); +} + /* Register an interface and its bundles. */ int gb_interface_add(struct gb_interface *intf) { @@ -268,3 +257,16 @@ int gb_interface_add(struct gb_interface *intf) return 0; } + +/* Deregister an interface and drop its reference. */ +void gb_interface_remove(struct gb_interface *intf) +{ + if (device_is_registered(&intf->dev)) { + device_del(&intf->dev); + dev_info(&intf->dev, "Interface removed\n"); + } + + list_del(&intf->links); + + put_device(&intf->dev); +} diff --git a/drivers/staging/greybus/interface.h b/drivers/staging/greybus/interface.h index 4b69e9ee9070..d4c55abae258 100644 --- a/drivers/staging/greybus/interface.h +++ b/drivers/staging/greybus/interface.h @@ -48,6 +48,7 @@ struct gb_interface *gb_interface_find(struct gb_host_device *hd, struct gb_interface *gb_interface_create(struct gb_host_device *hd, u8 interface_id); int gb_interface_enable(struct gb_interface *intf); +void gb_interface_disable(struct gb_interface *intf); int gb_interface_add(struct gb_interface *intf); void gb_interface_remove(struct gb_interface *intf); diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c index 631a76965b53..480a0712018d 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/staging/greybus/svc.c @@ -533,12 +533,9 @@ static void gb_svc_intf_remove(struct gb_svc *svc, struct gb_interface *intf) { intf->disconnected = true; - get_device(&intf->dev); - - gb_interface_remove(intf); + gb_interface_disable(intf); gb_svc_interface_route_destroy(svc, intf); - - put_device(&intf->dev); + gb_interface_remove(intf); } static void gb_svc_process_intf_hotplug(struct gb_operation *operation) @@ -1001,8 +998,10 @@ static void gb_svc_remove_interfaces(struct gb_svc *svc) { struct gb_interface *intf, *tmp; - list_for_each_entry_safe(intf, tmp, &svc->hd->interfaces, links) + list_for_each_entry_safe(intf, tmp, &svc->hd->interfaces, links) { + gb_interface_disable(intf); gb_interface_remove(intf); + } } void gb_svc_del(struct gb_svc *svc)