aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFernando Guzman Lugo <fernando.lugo@ti.com>2012-08-30 14:26:13 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2012-09-18 05:53:33 -0400
commit70b85ef83ce3523f709b622d2c4cb31778686338 (patch)
treeeeda85e263ef33f247d97280b367ff3b0f46c1b6
parent8afd519c3470f685f964deebd61aa51d83cde90a (diff)
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>
-rw-r--r--drivers/remoteproc/remoteproc_core.c84
-rw-r--r--drivers/remoteproc/remoteproc_internal.h1
-rw-r--r--include/linux/remoteproc.h2
3 files changed, 65 insertions, 22 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 93e2b3526543..5000d7589cf5 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -884,6 +884,60 @@ out:
884 complete_all(&rproc->firmware_loading_complete); 884 complete_all(&rproc->firmware_loading_complete);
885} 885}
886 886
887static int rproc_add_virtio_devices(struct rproc *rproc)
888{
889 int ret;
890
891 /* rproc_del() calls must wait until async loader completes */
892 init_completion(&rproc->firmware_loading_complete);
893
894 /*
895 * We must retrieve early virtio configuration info from
896 * the firmware (e.g. whether to register a virtio device,
897 * what virtio features does it support, ...).
898 *
899 * We're initiating an asynchronous firmware loading, so we can
900 * be built-in kernel code, without hanging the boot process.
901 */
902 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
903 rproc->firmware, &rproc->dev, GFP_KERNEL,
904 rproc, rproc_fw_config_virtio);
905 if (ret < 0) {
906 dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret);
907 complete_all(&rproc->firmware_loading_complete);
908 }
909
910 return ret;
911}
912
913/**
914 * rproc_trigger_recovery() - recover a remoteproc
915 * @rproc: the remote processor
916 *
917 * The recovery is done by reseting all the virtio devices, that way all the
918 * rpmsg drivers will be reseted along with the remote processor making the
919 * remoteproc functional again.
920 *
921 * This function can sleep, so it cannot be called from atomic context.
922 */
923int rproc_trigger_recovery(struct rproc *rproc)
924{
925 struct rproc_vdev *rvdev, *rvtmp;
926
927 dev_err(&rproc->dev, "recovering %s\n", rproc->name);
928
929 init_completion(&rproc->crash_comp);
930
931 /* clean up remote vdev entries */
932 list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
933 rproc_remove_virtio_dev(rvdev);
934
935 /* wait until there is no more rproc users */
936 wait_for_completion(&rproc->crash_comp);
937
938 return rproc_add_virtio_devices(rproc);
939}
940
887/** 941/**
888 * rproc_crash_handler_work() - handle a crash 942 * rproc_crash_handler_work() - handle a crash
889 * 943 *
@@ -911,7 +965,7 @@ static void rproc_crash_handler_work(struct work_struct *work)
911 965
912 mutex_unlock(&rproc->lock); 966 mutex_unlock(&rproc->lock);
913 967
914 /* TODO: handle crash */ 968 rproc_trigger_recovery(rproc);
915} 969}
916 970
917/** 971/**
@@ -1035,6 +1089,10 @@ void rproc_shutdown(struct rproc *rproc)
1035 1089
1036 rproc_disable_iommu(rproc); 1090 rproc_disable_iommu(rproc);
1037 1091
1092 /* if in crash state, unlock crash handler */
1093 if (rproc->state == RPROC_CRASHED)
1094 complete_all(&rproc->crash_comp);
1095
1038 rproc->state = RPROC_OFFLINE; 1096 rproc->state = RPROC_OFFLINE;
1039 1097
1040 dev_info(dev, "stopped remote processor %s\n", rproc->name); 1098 dev_info(dev, "stopped remote processor %s\n", rproc->name);
@@ -1069,7 +1127,7 @@ EXPORT_SYMBOL(rproc_shutdown);
1069int rproc_add(struct rproc *rproc) 1127int rproc_add(struct rproc *rproc)
1070{ 1128{
1071 struct device *dev = &rproc->dev; 1129 struct device *dev = &rproc->dev;
1072 int ret = 0; 1130 int ret;
1073 1131
1074 ret = device_add(dev); 1132 ret = device_add(dev);
1075 if (ret < 0) 1133 if (ret < 0)
@@ -1083,26 +1141,7 @@ int rproc_add(struct rproc *rproc)
1083 /* create debugfs entries */ 1141 /* create debugfs entries */
1084 rproc_create_debug_dir(rproc); 1142 rproc_create_debug_dir(rproc);
1085 1143
1086 /* rproc_del() calls must wait until async loader completes */ 1144 return rproc_add_virtio_devices(rproc);
1087 init_completion(&rproc->firmware_loading_complete);
1088
1089 /*
1090 * We must retrieve early virtio configuration info from
1091 * the firmware (e.g. whether to register a virtio device,
1092 * what virtio features does it support, ...).
1093 *
1094 * We're initiating an asynchronous firmware loading, so we can
1095 * be built-in kernel code, without hanging the boot process.
1096 */
1097 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
1098 rproc->firmware, dev, GFP_KERNEL,
1099 rproc, rproc_fw_config_virtio);
1100 if (ret < 0) {
1101 dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
1102 complete_all(&rproc->firmware_loading_complete);
1103 }
1104
1105 return ret;
1106} 1145}
1107EXPORT_SYMBOL(rproc_add); 1146EXPORT_SYMBOL(rproc_add);
1108 1147
@@ -1209,6 +1248,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1209 INIT_LIST_HEAD(&rproc->rvdevs); 1248 INIT_LIST_HEAD(&rproc->rvdevs);
1210 1249
1211 INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work); 1250 INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
1251 init_completion(&rproc->crash_comp);
1212 1252
1213 rproc->state = RPROC_OFFLINE; 1253 rproc->state = RPROC_OFFLINE;
1214 1254
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index a690ebe7aa51..7bb66482d061 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -63,6 +63,7 @@ void rproc_free_vring(struct rproc_vring *rvring);
63int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); 63int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
64 64
65void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); 65void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
66int rproc_trigger_recovery(struct rproc *rproc);
66 67
67static inline 68static inline
68int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) 69int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index a46ed2723803..0c1a2f95be76 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -398,6 +398,7 @@ enum rproc_crash_type {
398 * @index: index of this rproc device 398 * @index: index of this rproc device
399 * @crash_handler: workqueue for handling a crash 399 * @crash_handler: workqueue for handling a crash
400 * @crash_cnt: crash counter 400 * @crash_cnt: crash counter
401 * @crash_comp: completion used to sync crash handler and the rproc reload
401 */ 402 */
402struct rproc { 403struct rproc {
403 struct klist_node node; 404 struct klist_node node;
@@ -423,6 +424,7 @@ struct rproc {
423 int index; 424 int index;
424 struct work_struct crash_handler; 425 struct work_struct crash_handler;
425 unsigned crash_cnt; 426 unsigned crash_cnt;
427 struct completion crash_comp;
426}; 428};
427 429
428/* we currently support only two vrings per rvdev */ 430/* we currently support only two vrings per rvdev */