diff options
Diffstat (limited to 'drivers/remoteproc/remoteproc_core.c')
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 79 |
1 files changed, 75 insertions, 4 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index d5c2dbfc7443..93e2b3526543 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -50,6 +50,18 @@ typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); | |||
50 | /* Unique indices for remoteproc devices */ | 50 | /* Unique indices for remoteproc devices */ |
51 | static DEFINE_IDA(rproc_dev_index); | 51 | static DEFINE_IDA(rproc_dev_index); |
52 | 52 | ||
53 | static const char * const rproc_crash_names[] = { | ||
54 | [RPROC_MMUFAULT] = "mmufault", | ||
55 | }; | ||
56 | |||
57 | /* translate rproc_crash_type to string */ | ||
58 | static const char *rproc_crash_to_string(enum rproc_crash_type type) | ||
59 | { | ||
60 | if (type < ARRAY_SIZE(rproc_crash_names)) | ||
61 | return rproc_crash_names[type]; | ||
62 | return "unkown"; | ||
63 | } | ||
64 | |||
53 | /* | 65 | /* |
54 | * This is the IOMMU fault handler we register with the IOMMU API | 66 | * This is the IOMMU fault handler we register with the IOMMU API |
55 | * (when relevant; not all remote processors access memory through | 67 | * (when relevant; not all remote processors access memory through |
@@ -57,18 +69,19 @@ static DEFINE_IDA(rproc_dev_index); | |||
57 | * | 69 | * |
58 | * IOMMU core will invoke this handler whenever the remote processor | 70 | * IOMMU core will invoke this handler whenever the remote processor |
59 | * will try to access an unmapped device address. | 71 | * will try to access an unmapped device address. |
60 | * | ||
61 | * Currently this is mostly a stub, but it will be later used to trigger | ||
62 | * the recovery of the remote processor. | ||
63 | */ | 72 | */ |
64 | static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, | 73 | static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, |
65 | unsigned long iova, int flags, void *token) | 74 | unsigned long iova, int flags, void *token) |
66 | { | 75 | { |
76 | struct rproc *rproc = token; | ||
77 | |||
67 | dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); | 78 | dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); |
68 | 79 | ||
80 | rproc_report_crash(rproc, RPROC_MMUFAULT); | ||
81 | |||
69 | /* | 82 | /* |
70 | * Let the iommu core know we're not really handling this fault; | 83 | * Let the iommu core know we're not really handling this fault; |
71 | * we just plan to use this as a recovery trigger. | 84 | * we just used it as a recovery trigger. |
72 | */ | 85 | */ |
73 | return -ENOSYS; | 86 | return -ENOSYS; |
74 | } | 87 | } |
@@ -872,6 +885,36 @@ out: | |||
872 | } | 885 | } |
873 | 886 | ||
874 | /** | 887 | /** |
888 | * rproc_crash_handler_work() - handle a crash | ||
889 | * | ||
890 | * This function needs to handle everything related to a crash, like cpu | ||
891 | * registers and stack dump, information to help to debug the fatal error, etc. | ||
892 | */ | ||
893 | static void rproc_crash_handler_work(struct work_struct *work) | ||
894 | { | ||
895 | struct rproc *rproc = container_of(work, struct rproc, crash_handler); | ||
896 | struct device *dev = &rproc->dev; | ||
897 | |||
898 | dev_dbg(dev, "enter %s\n", __func__); | ||
899 | |||
900 | mutex_lock(&rproc->lock); | ||
901 | |||
902 | if (rproc->state == RPROC_CRASHED || rproc->state == RPROC_OFFLINE) { | ||
903 | /* handle only the first crash detected */ | ||
904 | mutex_unlock(&rproc->lock); | ||
905 | return; | ||
906 | } | ||
907 | |||
908 | rproc->state = RPROC_CRASHED; | ||
909 | dev_err(dev, "handling crash #%u in %s\n", ++rproc->crash_cnt, | ||
910 | rproc->name); | ||
911 | |||
912 | mutex_unlock(&rproc->lock); | ||
913 | |||
914 | /* TODO: handle crash */ | ||
915 | } | ||
916 | |||
917 | /** | ||
875 | * rproc_boot() - boot a remote processor | 918 | * rproc_boot() - boot a remote processor |
876 | * @rproc: handle of a remote processor | 919 | * @rproc: handle of a remote processor |
877 | * | 920 | * |
@@ -1165,6 +1208,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, | |||
1165 | INIT_LIST_HEAD(&rproc->traces); | 1208 | INIT_LIST_HEAD(&rproc->traces); |
1166 | INIT_LIST_HEAD(&rproc->rvdevs); | 1209 | INIT_LIST_HEAD(&rproc->rvdevs); |
1167 | 1210 | ||
1211 | INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work); | ||
1212 | |||
1168 | rproc->state = RPROC_OFFLINE; | 1213 | rproc->state = RPROC_OFFLINE; |
1169 | 1214 | ||
1170 | return rproc; | 1215 | return rproc; |
@@ -1221,6 +1266,32 @@ int rproc_del(struct rproc *rproc) | |||
1221 | } | 1266 | } |
1222 | EXPORT_SYMBOL(rproc_del); | 1267 | EXPORT_SYMBOL(rproc_del); |
1223 | 1268 | ||
1269 | /** | ||
1270 | * rproc_report_crash() - rproc crash reporter function | ||
1271 | * @rproc: remote processor | ||
1272 | * @type: crash type | ||
1273 | * | ||
1274 | * This function must be called every time a crash is detected by the low-level | ||
1275 | * drivers implementing a specific remoteproc. This should not be called from a | ||
1276 | * non-remoteproc driver. | ||
1277 | * | ||
1278 | * This function can be called from atomic/interrupt context. | ||
1279 | */ | ||
1280 | void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) | ||
1281 | { | ||
1282 | if (!rproc) { | ||
1283 | pr_err("NULL rproc pointer\n"); | ||
1284 | return; | ||
1285 | } | ||
1286 | |||
1287 | dev_err(&rproc->dev, "crash detected in %s: type %s\n", | ||
1288 | rproc->name, rproc_crash_to_string(type)); | ||
1289 | |||
1290 | /* create a new task to handle the error */ | ||
1291 | schedule_work(&rproc->crash_handler); | ||
1292 | } | ||
1293 | EXPORT_SYMBOL(rproc_report_crash); | ||
1294 | |||
1224 | static int __init remoteproc_init(void) | 1295 | static int __init remoteproc_init(void) |
1225 | { | 1296 | { |
1226 | rproc_init_debugfs(); | 1297 | rproc_init_debugfs(); |