greybus: svc: Allow consecutive hotplug events for the same module
There are two cases where the AP may receive hotplug event for an existing interface, without first getting a hot-unplug request for it. - bootrom loading the firmware image and booting into that, which only generates a hotplug event. i.e. no hot-unplug event, as the module never went away. - Or the firmware on the module crashed and sent hotplug request again to the SVC, which got propagated to AP. Handle such cases by first removing the interface, with a clear print message shown to the user. And then following the normal hotplug sequence to add the interface. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
parent
c06307c3b4
commit
bbaca71151
|
@ -329,6 +329,25 @@ static int gb_svc_hello(struct gb_operation *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void svc_intf_remove(struct gb_connection *connection,
|
||||
struct gb_interface *intf)
|
||||
{
|
||||
struct greybus_host_device *hd = connection->hd;
|
||||
struct gb_svc *svc = connection->private;
|
||||
u8 intf_id = intf->interface_id;
|
||||
u8 device_id;
|
||||
|
||||
device_id = intf->device_id;
|
||||
gb_interface_remove(hd, intf_id);
|
||||
|
||||
/*
|
||||
* Destroy the two-way route between the AP and the interface.
|
||||
*/
|
||||
gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
|
||||
|
||||
ida_simple_remove(&svc->device_id_map, device_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
|
||||
* returns, irrespective of success or Failure in bringing up the module.
|
||||
|
@ -351,6 +370,27 @@ static void svc_process_hotplug(struct work_struct *work)
|
|||
*/
|
||||
intf_id = hotplug->intf_id;
|
||||
|
||||
intf = gb_interface_find(hd, intf_id);
|
||||
if (intf) {
|
||||
/*
|
||||
* We have received a hotplug request for an interface that
|
||||
* already exists.
|
||||
*
|
||||
* This can happen in cases like:
|
||||
* - bootrom loading the firmware image and booting into that,
|
||||
* which only generates a hotplug event. i.e. no hot-unplug
|
||||
* event.
|
||||
* - Or the firmware on the module crashed and sent hotplug
|
||||
* request again to the SVC, which got propagated to AP.
|
||||
*
|
||||
* Remove the interface and add it again, and let user know
|
||||
* about this with a print message.
|
||||
*/
|
||||
dev_info(dev, "Removed interface (%hhu) to add it again\n",
|
||||
intf_id);
|
||||
svc_intf_remove(connection, intf);
|
||||
}
|
||||
|
||||
intf = gb_interface_create(hd, intf_id);
|
||||
if (!intf) {
|
||||
dev_err(dev, "%s: Failed to create interface with id %hhu\n",
|
||||
|
@ -463,8 +503,6 @@ static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
|
|||
struct gb_svc_intf_hot_unplug_request *hot_unplug = request->payload;
|
||||
struct greybus_host_device *hd = op->connection->hd;
|
||||
struct device *dev = &op->connection->dev;
|
||||
struct gb_svc *svc = op->connection->private;
|
||||
u8 device_id;
|
||||
struct gb_interface *intf;
|
||||
u8 intf_id;
|
||||
|
||||
|
@ -483,15 +521,7 @@ static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
device_id = intf->device_id;
|
||||
gb_interface_remove(hd, intf_id);
|
||||
|
||||
/*
|
||||
* Destroy the two-way route between the AP and the interface.
|
||||
*/
|
||||
gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
|
||||
|
||||
ida_simple_remove(&svc->device_id_map, device_id);
|
||||
svc_intf_remove(op->connection, intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue