From 62491622db9c9b6a51630f4c8c653f59c2c834f9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 20 Jul 2016 16:40:23 +0200 Subject: [PATCH] greybus: interface: make sure type is invariant during reactivation An interface is not expected to change its type after a power down and reactivation so make sure to treat that as a fatal error. This is complicated by the current Toshiba ES3 hack which requires us to retry activation as Greybus interfaces are sometimes misdetected as UniPro interfaces. Handle that by only retrying activation the first time an interface is activated, and for interfaces already detected as having Greybus type. Signed-off-by: Johan Hovold Reviewed-by: Alex Elder Reviewed-by: Viresh Kumar Reviewed-by: Sandeep Patil Reviewed-by: Patrick Titiano Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/interface.c | 75 +++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index 8e1b6c0..01cefce 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -822,7 +822,8 @@ static int gb_interface_unipro_set(struct gb_interface *intf, bool enable) return 0; } -static int gb_interface_activate_operation(struct gb_interface *intf) +static int gb_interface_activate_operation(struct gb_interface *intf, + enum gb_interface_type *intf_type) { struct gb_svc *svc = intf->hd->svc; u8 type; @@ -838,20 +839,20 @@ static int gb_interface_activate_operation(struct gb_interface *intf) switch (type) { case GB_SVC_INTF_TYPE_DUMMY: - intf->type = GB_INTERFACE_TYPE_DUMMY; + *intf_type = GB_INTERFACE_TYPE_DUMMY; /* FIXME: handle as an error for now */ return -ENODEV; case GB_SVC_INTF_TYPE_UNIPRO: - intf->type = GB_INTERFACE_TYPE_UNIPRO; + *intf_type = GB_INTERFACE_TYPE_UNIPRO; dev_err(&intf->dev, "interface type UniPro not supported\n"); /* FIXME: handle as an error for now */ return -ENODEV; case GB_SVC_INTF_TYPE_GREYBUS: - intf->type = GB_INTERFACE_TYPE_GREYBUS; + *intf_type = GB_INTERFACE_TYPE_GREYBUS; break; default: dev_err(&intf->dev, "unknown interface type: %u\n", type); - intf->type = GB_INTERFACE_TYPE_UNKNOWN; + *intf_type = GB_INTERFACE_TYPE_UNKNOWN; return -ENODEV; } @@ -865,10 +866,13 @@ static int gb_interface_hibernate_link(struct gb_interface *intf) return gb_svc_intf_set_power_mode_hibernate(svc, intf->interface_id); } -static int _gb_interface_activate(struct gb_interface *intf) +static int _gb_interface_activate(struct gb_interface *intf, + enum gb_interface_type *type) { int ret; + *type = GB_INTERFACE_TYPE_UNKNOWN; + if (intf->ejected) return -ENODEV; @@ -884,7 +888,7 @@ static int _gb_interface_activate(struct gb_interface *intf) if (ret) goto err_refclk_disable; - ret = gb_interface_activate_operation(intf); + ret = gb_interface_activate_operation(intf, type); if (ret) goto err_unipro_disable; @@ -915,26 +919,21 @@ err_vsys_disable: } /* - * Activate an interface. + * 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. * - * Locking: Caller holds the interface mutex. + * FIXME: Check if this is a Toshiba bridge before retrying? */ -int gb_interface_activate(struct gb_interface *intf) +static int _gb_interface_activate_es3_hack(struct gb_interface *intf, + enum gb_interface_type *type) { int retries = 3; int ret; - /* - * 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. - * - * FIXME: Check if this is a Toshiba bridge before retrying? - */ while (retries--) { - ret = _gb_interface_activate(intf); - if (ret == -ENODEV && intf->type == GB_SVC_INTF_TYPE_UNIPRO) + ret = _gb_interface_activate(intf, type); + if (ret == -ENODEV && *type == GB_INTERFACE_TYPE_UNIPRO) continue; break; @@ -944,6 +943,42 @@ int gb_interface_activate(struct gb_interface *intf) } /* + * Activate an interface. + * + * Locking: Caller holds the interface mutex. + */ +int gb_interface_activate(struct gb_interface *intf) +{ + enum gb_interface_type type; + int ret; + + switch (intf->type) { + case GB_INTERFACE_TYPE_INVALID: + case GB_INTERFACE_TYPE_GREYBUS: + ret = _gb_interface_activate_es3_hack(intf, &type); + break; + default: + ret = _gb_interface_activate(intf, &type); + } + + /* Make sure type is detected correctly during reactivation. */ + if (intf->type != GB_INTERFACE_TYPE_INVALID) { + if (type != intf->type) { + dev_err(&intf->dev, "failed to detect interface type\n"); + + if (!ret) + gb_interface_deactivate(intf); + + return -EIO; + } + } else { + intf->type = type; + } + + return ret; +} + +/* * Deactivate an interface. * * Locking: Caller holds the interface mutex. -- 2.7.4