From 7aefe7918f8e053f9cd8077fcc98182689f1341e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 27 May 2016 17:26:22 +0200 Subject: [PATCH] greybus: core: avoid I/O to disconnected interfaces Add new helper to disable connections to interfaces that have already been disconnected (e.g. forcibly removed). The connection tear-down procedure differs enough depending on whether the interface is still present or already gone to warrant a dedicated helper. This will become more obvious with the new tear-down procedure, which involves I/O on the connection being tore down. This also simplifies handling of the legacy bootrom, which does not support the new tear-down operations. Specifically, this allows us to remove the early control-connection tear down during interface disable, and also avoids some error messages currently printed during legacy mode switch (i.e. bootrom boot-over-UniPro) and forcible removal. Reviewed-by: Viresh Kumar Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 21 +++++++++++++++++++++ drivers/staging/greybus/connection.h | 1 + drivers/staging/greybus/control.c | 5 ++++- drivers/staging/greybus/core.c | 2 +- drivers/staging/greybus/interface.c | 7 ------- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index ac3be2fceade..7e07ef832b7c 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -654,6 +654,27 @@ out_unlock: } EXPORT_SYMBOL_GPL(gb_connection_disable); +/* Disable a connection without communicating with the remote end. */ +void gb_connection_disable_forced(struct gb_connection *connection) +{ + mutex_lock(&connection->mutex); + + if (connection->state == GB_CONNECTION_STATE_DISABLED) + goto out_unlock; + + spin_lock_irq(&connection->lock); + connection->state = GB_CONNECTION_STATE_DISABLED; + gb_connection_cancel_operations(connection, -ESHUTDOWN); + spin_unlock_irq(&connection->lock); + + gb_connection_svc_connection_destroy(connection); + gb_connection_hd_cport_disable(connection); + +out_unlock: + mutex_unlock(&connection->mutex); +} +EXPORT_SYMBOL_GPL(gb_connection_disable_forced); + /* Caller must have disabled the connection before destroying it. */ void gb_connection_destroy(struct gb_connection *connection) { diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index 53ce28452da4..f1592391acf1 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -80,6 +80,7 @@ int gb_connection_enable(struct gb_connection *connection); int gb_connection_enable_tx(struct gb_connection *connection); void gb_connection_disable_rx(struct gb_connection *connection); void gb_connection_disable(struct gb_connection *connection); +void gb_connection_disable_forced(struct gb_connection *connection); void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id, u8 *data, size_t length); diff --git a/drivers/staging/greybus/control.c b/drivers/staging/greybus/control.c index b4a1c1476c56..a5effcf09f56 100644 --- a/drivers/staging/greybus/control.c +++ b/drivers/staging/greybus/control.c @@ -316,7 +316,10 @@ void gb_control_disable(struct gb_control *control) { dev_dbg(&control->connection->intf->dev, "%s\n", __func__); - gb_connection_disable(control->connection); + if (control->intf->disconnected) + gb_connection_disable_forced(control->connection); + else + gb_connection_disable(control->connection); } int gb_control_add(struct gb_control *control) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index b1a7b116843a..7350c5eba7e9 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -189,7 +189,7 @@ static int greybus_remove(struct device *dev) list_for_each_entry(connection, &bundle->connections, bundle_links) { if (bundle->intf->disconnected) - gb_connection_disable(connection); + gb_connection_disable_forced(connection); else gb_connection_disable_rx(connection); } diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index c19a09cea462..d1e2c456462e 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -671,13 +671,6 @@ void gb_interface_disable(struct gb_interface *intf) trace_gb_interface_disable(intf); - /* - * 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); -- 2.20.1