greybus: interface: retry enumeration of UniPro-only modules

Greybus modules will sometimes fail to send the mailbox poke and
erroneously be enumerated as UniPro-only modules. The root cause for
this on the module side is not fully understand, but it seems that this
may be due to "the bootrom bug:" a known problem with the bootrom where
linkup will occasionally fail because of a race condition.

Before the new hotplug code was implemented in the firmware, the SVC
would retry enumeration of modules that did not send the mailbox poke;
this patch ports that functionality to the AP.

Signed-off-by: Jeffrey Carlyle <jcarlyle@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Jeffrey Carlyle 2016-05-18 18:55:13 -07:00 committed by Greg Kroah-Hartman
parent 9bc63b7ff5
commit e16715c135
2 changed files with 22 additions and 2 deletions

View File

@ -447,7 +447,8 @@ static int gb_interface_activate_operation(struct gb_interface *intf)
return -ENODEV;
case GB_SVC_INTF_TYPE_UNIPRO:
dev_err(&intf->dev, "interface type UniPro not supported\n");
return -ENODEV;
/* FIXME: check if this is a Toshiba bridge before retrying? */
return -EAGAIN;
case GB_SVC_INTF_TYPE_GREYBUS:
break;
default:

View File

@ -138,13 +138,32 @@ static void gb_module_register_interface(struct gb_interface *intf)
struct gb_module *module = intf->module;
u8 intf_id = intf->interface_id;
int ret;
int retries = 3;
mutex_lock(&intf->mutex);
ret = gb_interface_activate(intf);
while (retries--) {
ret = gb_interface_activate(intf);
if (ret != -EAGAIN)
break;
}
if (ret) {
dev_err(&module->dev, "failed to activate interface %u: %d\n",
intf_id, ret);
/*
* -EAGAIN indicates that the Greybus operation
* interface_activate determined the remote interface to be
* UniPro-only. 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. If we exhause our
* retries trying to activate such an interface, convert
* the error code back into a "no device" error.
*/
if (ret == -EAGAIN)
ret = -ENODEV;
gb_interface_add(intf);
goto err_unlock;
}