remoteproc: add actual recovery implementation
Add rproc_trigger_recovery() which takes care of the recovery itself, by removing, and re-adding, all of the remoteproc's virtio devices. This resets all virtio users of the remote processor, during which the remote processor is powered off and on again. Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com> [ohad: introduce rproc_add_virtio_devices to avoid 1.copying code 2.anomaly] [ohad: some white space, naming and commit log changes] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
This commit is contained in:
parent
8afd519c34
commit
70b85ef83c
|
@ -884,6 +884,60 @@ out:
|
||||||
complete_all(&rproc->firmware_loading_complete);
|
complete_all(&rproc->firmware_loading_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rproc_add_virtio_devices(struct rproc *rproc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* rproc_del() calls must wait until async loader completes */
|
||||||
|
init_completion(&rproc->firmware_loading_complete);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must retrieve early virtio configuration info from
|
||||||
|
* the firmware (e.g. whether to register a virtio device,
|
||||||
|
* what virtio features does it support, ...).
|
||||||
|
*
|
||||||
|
* We're initiating an asynchronous firmware loading, so we can
|
||||||
|
* be built-in kernel code, without hanging the boot process.
|
||||||
|
*/
|
||||||
|
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
|
||||||
|
rproc->firmware, &rproc->dev, GFP_KERNEL,
|
||||||
|
rproc, rproc_fw_config_virtio);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret);
|
||||||
|
complete_all(&rproc->firmware_loading_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rproc_trigger_recovery() - recover a remoteproc
|
||||||
|
* @rproc: the remote processor
|
||||||
|
*
|
||||||
|
* The recovery is done by reseting all the virtio devices, that way all the
|
||||||
|
* rpmsg drivers will be reseted along with the remote processor making the
|
||||||
|
* remoteproc functional again.
|
||||||
|
*
|
||||||
|
* This function can sleep, so it cannot be called from atomic context.
|
||||||
|
*/
|
||||||
|
int rproc_trigger_recovery(struct rproc *rproc)
|
||||||
|
{
|
||||||
|
struct rproc_vdev *rvdev, *rvtmp;
|
||||||
|
|
||||||
|
dev_err(&rproc->dev, "recovering %s\n", rproc->name);
|
||||||
|
|
||||||
|
init_completion(&rproc->crash_comp);
|
||||||
|
|
||||||
|
/* clean up remote vdev entries */
|
||||||
|
list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
|
||||||
|
rproc_remove_virtio_dev(rvdev);
|
||||||
|
|
||||||
|
/* wait until there is no more rproc users */
|
||||||
|
wait_for_completion(&rproc->crash_comp);
|
||||||
|
|
||||||
|
return rproc_add_virtio_devices(rproc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rproc_crash_handler_work() - handle a crash
|
* rproc_crash_handler_work() - handle a crash
|
||||||
*
|
*
|
||||||
|
@ -911,7 +965,7 @@ static void rproc_crash_handler_work(struct work_struct *work)
|
||||||
|
|
||||||
mutex_unlock(&rproc->lock);
|
mutex_unlock(&rproc->lock);
|
||||||
|
|
||||||
/* TODO: handle crash */
|
rproc_trigger_recovery(rproc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1035,6 +1089,10 @@ void rproc_shutdown(struct rproc *rproc)
|
||||||
|
|
||||||
rproc_disable_iommu(rproc);
|
rproc_disable_iommu(rproc);
|
||||||
|
|
||||||
|
/* if in crash state, unlock crash handler */
|
||||||
|
if (rproc->state == RPROC_CRASHED)
|
||||||
|
complete_all(&rproc->crash_comp);
|
||||||
|
|
||||||
rproc->state = RPROC_OFFLINE;
|
rproc->state = RPROC_OFFLINE;
|
||||||
|
|
||||||
dev_info(dev, "stopped remote processor %s\n", rproc->name);
|
dev_info(dev, "stopped remote processor %s\n", rproc->name);
|
||||||
|
@ -1069,7 +1127,7 @@ EXPORT_SYMBOL(rproc_shutdown);
|
||||||
int rproc_add(struct rproc *rproc)
|
int rproc_add(struct rproc *rproc)
|
||||||
{
|
{
|
||||||
struct device *dev = &rproc->dev;
|
struct device *dev = &rproc->dev;
|
||||||
int ret = 0;
|
int ret;
|
||||||
|
|
||||||
ret = device_add(dev);
|
ret = device_add(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1083,26 +1141,7 @@ int rproc_add(struct rproc *rproc)
|
||||||
/* create debugfs entries */
|
/* create debugfs entries */
|
||||||
rproc_create_debug_dir(rproc);
|
rproc_create_debug_dir(rproc);
|
||||||
|
|
||||||
/* rproc_del() calls must wait until async loader completes */
|
return rproc_add_virtio_devices(rproc);
|
||||||
init_completion(&rproc->firmware_loading_complete);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We must retrieve early virtio configuration info from
|
|
||||||
* the firmware (e.g. whether to register a virtio device,
|
|
||||||
* what virtio features does it support, ...).
|
|
||||||
*
|
|
||||||
* We're initiating an asynchronous firmware loading, so we can
|
|
||||||
* be built-in kernel code, without hanging the boot process.
|
|
||||||
*/
|
|
||||||
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
|
|
||||||
rproc->firmware, dev, GFP_KERNEL,
|
|
||||||
rproc, rproc_fw_config_virtio);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
|
|
||||||
complete_all(&rproc->firmware_loading_complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rproc_add);
|
EXPORT_SYMBOL(rproc_add);
|
||||||
|
|
||||||
|
@ -1209,6 +1248,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
||||||
INIT_LIST_HEAD(&rproc->rvdevs);
|
INIT_LIST_HEAD(&rproc->rvdevs);
|
||||||
|
|
||||||
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
|
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
|
||||||
|
init_completion(&rproc->crash_comp);
|
||||||
|
|
||||||
rproc->state = RPROC_OFFLINE;
|
rproc->state = RPROC_OFFLINE;
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ void rproc_free_vring(struct rproc_vring *rvring);
|
||||||
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
|
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
|
||||||
|
|
||||||
void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
|
void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
|
||||||
|
int rproc_trigger_recovery(struct rproc *rproc);
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
|
int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
|
||||||
|
|
|
@ -398,6 +398,7 @@ enum rproc_crash_type {
|
||||||
* @index: index of this rproc device
|
* @index: index of this rproc device
|
||||||
* @crash_handler: workqueue for handling a crash
|
* @crash_handler: workqueue for handling a crash
|
||||||
* @crash_cnt: crash counter
|
* @crash_cnt: crash counter
|
||||||
|
* @crash_comp: completion used to sync crash handler and the rproc reload
|
||||||
*/
|
*/
|
||||||
struct rproc {
|
struct rproc {
|
||||||
struct klist_node node;
|
struct klist_node node;
|
||||||
|
@ -423,6 +424,7 @@ struct rproc {
|
||||||
int index;
|
int index;
|
||||||
struct work_struct crash_handler;
|
struct work_struct crash_handler;
|
||||||
unsigned crash_cnt;
|
unsigned crash_cnt;
|
||||||
|
struct completion crash_comp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* we currently support only two vrings per rvdev */
|
/* we currently support only two vrings per rvdev */
|
||||||
|
|
Loading…
Reference in New Issue