diff options
| author | Fernando Guzman Lugo <fernando.lugo@ti.com> | 2012-08-30 14:26:13 -0400 |
|---|---|---|
| committer | Ohad Ben-Cohen <ohad@wizery.com> | 2012-09-18 05:53:33 -0400 |
| commit | 70b85ef83ce3523f709b622d2c4cb31778686338 (patch) | |
| tree | eeda85e263ef33f247d97280b367ff3b0f46c1b6 | |
| parent | 8afd519c3470f685f964deebd61aa51d83cde90a (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.c | 84 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_internal.h | 1 | ||||
| -rw-r--r-- | include/linux/remoteproc.h | 2 |
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 | ||
| 887 | static 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 | */ | ||
| 923 | int 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); | |||
| 1069 | int rproc_add(struct rproc *rproc) | 1127 | int 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 | } |
| 1107 | EXPORT_SYMBOL(rproc_add); | 1146 | EXPORT_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); | |||
| 63 | int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); | 63 | int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); |
| 64 | 64 | ||
| 65 | void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); | 65 | void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); |
| 66 | int rproc_trigger_recovery(struct rproc *rproc); | ||
| 66 | 67 | ||
| 67 | static inline | 68 | static inline |
| 68 | int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) | 69 | int 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 | */ |
| 402 | struct rproc { | 403 | struct 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 */ |
