aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/Kconfig14
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/omap_remoteproc.c3
-rw-r--r--drivers/remoteproc/remoteproc_core.c209
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c85
-rw-r--r--drivers/remoteproc/remoteproc_internal.h1
-rw-r--r--drivers/remoteproc/ste_modem_rproc.c322
7 files changed, 593 insertions, 42 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f8d818abf98c..96ce101b9067 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -4,11 +4,14 @@ menu "Remoteproc drivers (EXPERIMENTAL)"
4config REMOTEPROC 4config REMOTEPROC
5 tristate 5 tristate
6 depends on EXPERIMENTAL 6 depends on EXPERIMENTAL
7 depends on HAS_DMA
7 select FW_CONFIG 8 select FW_CONFIG
9 select VIRTIO
8 10
9config OMAP_REMOTEPROC 11config OMAP_REMOTEPROC
10 tristate "OMAP remoteproc support" 12 tristate "OMAP remoteproc support"
11 depends on EXPERIMENTAL 13 depends on EXPERIMENTAL
14 depends on HAS_DMA
12 depends on ARCH_OMAP4 15 depends on ARCH_OMAP4
13 depends on OMAP_IOMMU 16 depends on OMAP_IOMMU
14 select REMOTEPROC 17 select REMOTEPROC
@@ -27,4 +30,15 @@ config OMAP_REMOTEPROC
27 It's safe to say n here if you're not interested in multimedia 30 It's safe to say n here if you're not interested in multimedia
28 offloading or just want a bare minimum kernel. 31 offloading or just want a bare minimum kernel.
29 32
33config STE_MODEM_RPROC
34 tristate "STE-Modem remoteproc support"
35 depends on EXPERIMENTAL
36 depends on HAS_DMA
37 select REMOTEPROC
38 default n
39 help
40 Say y or m here to support STE-Modem shared memory driver.
41 This can be either built-in or a loadable module.
42 If unsure say N.
43
30endmenu 44endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 934ce6e2c66b..391b65181c05 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,3 +8,4 @@ remoteproc-y += remoteproc_debugfs.o
8remoteproc-y += remoteproc_virtio.o 8remoteproc-y += remoteproc_virtio.o
9remoteproc-y += remoteproc_elf_loader.o 9remoteproc-y += remoteproc_elf_loader.o
10obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o 10obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
11obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index b54504ee61f1..32c289c2ba13 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -116,6 +116,9 @@ static int omap_rproc_start(struct rproc *rproc)
116 struct omap_rproc_pdata *pdata = pdev->dev.platform_data; 116 struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
117 int ret; 117 int ret;
118 118
119 if (pdata->set_bootaddr)
120 pdata->set_bootaddr(rproc->bootaddr);
121
119 oproc->nb.notifier_call = omap_rproc_mbox_callback; 122 oproc->nb.notifier_call = omap_rproc_mbox_callback;
120 123
121 /* every omap rproc is assigned a mailbox instance for messaging */ 124 /* every omap rproc is assigned a mailbox instance for messaging */
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index d5c2dbfc7443..dd3bfaf1ad40 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 */
51static DEFINE_IDA(rproc_dev_index); 51static DEFINE_IDA(rproc_dev_index);
52 52
53static const char * const rproc_crash_names[] = {
54 [RPROC_MMUFAULT] = "mmufault",
55};
56
57/* translate rproc_crash_type to string */
58static 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 */
64static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, 73static 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}
@@ -215,8 +228,11 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
215 return ret; 228 return ret;
216 } 229 }
217 230
218 dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va, 231 /* Store largest notifyid */
219 dma, size, notifyid); 232 rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
233
234 dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
235 (unsigned long long)dma, size, notifyid);
220 236
221 rvring->va = va; 237 rvring->va = va;
222 rvring->dma = dma; 238 rvring->dma = dma;
@@ -256,13 +272,25 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
256 return 0; 272 return 0;
257} 273}
258 274
275static int rproc_max_notifyid(int id, void *p, void *data)
276{
277 int *maxid = data;
278 *maxid = max(*maxid, id);
279 return 0;
280}
281
259void rproc_free_vring(struct rproc_vring *rvring) 282void rproc_free_vring(struct rproc_vring *rvring)
260{ 283{
261 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); 284 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
262 struct rproc *rproc = rvring->rvdev->rproc; 285 struct rproc *rproc = rvring->rvdev->rproc;
286 int maxid = 0;
263 287
264 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); 288 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
265 idr_remove(&rproc->notifyids, rvring->notifyid); 289 idr_remove(&rproc->notifyids, rvring->notifyid);
290
291 /* Find the largest remaining notifyid */
292 idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
293 rproc->max_notifyid = maxid;
266} 294}
267 295
268/** 296/**
@@ -545,17 +573,10 @@ static int rproc_handle_carveout(struct rproc *rproc,
545 dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n", 573 dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n",
546 rsc->da, rsc->pa, rsc->len, rsc->flags); 574 rsc->da, rsc->pa, rsc->len, rsc->flags);
547 575
548 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
549 if (!mapping) {
550 dev_err(dev, "kzalloc mapping failed\n");
551 return -ENOMEM;
552 }
553
554 carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); 576 carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
555 if (!carveout) { 577 if (!carveout) {
556 dev_err(dev, "kzalloc carveout failed\n"); 578 dev_err(dev, "kzalloc carveout failed\n");
557 ret = -ENOMEM; 579 return -ENOMEM;
558 goto free_mapping;
559 } 580 }
560 581
561 va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); 582 va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL);
@@ -565,7 +586,8 @@ static int rproc_handle_carveout(struct rproc *rproc,
565 goto free_carv; 586 goto free_carv;
566 } 587 }
567 588
568 dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len); 589 dev_dbg(dev, "carveout va %p, dma %llx, len 0x%x\n", va,
590 (unsigned long long)dma, rsc->len);
569 591
570 /* 592 /*
571 * Ok, this is non-standard. 593 * Ok, this is non-standard.
@@ -585,11 +607,18 @@ static int rproc_handle_carveout(struct rproc *rproc,
585 * physical address in this case. 607 * physical address in this case.
586 */ 608 */
587 if (rproc->domain) { 609 if (rproc->domain) {
610 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
611 if (!mapping) {
612 dev_err(dev, "kzalloc mapping failed\n");
613 ret = -ENOMEM;
614 goto dma_free;
615 }
616
588 ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, 617 ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
589 rsc->flags); 618 rsc->flags);
590 if (ret) { 619 if (ret) {
591 dev_err(dev, "iommu_map failed: %d\n", ret); 620 dev_err(dev, "iommu_map failed: %d\n", ret);
592 goto dma_free; 621 goto free_mapping;
593 } 622 }
594 623
595 /* 624 /*
@@ -603,7 +632,8 @@ static int rproc_handle_carveout(struct rproc *rproc,
603 mapping->len = rsc->len; 632 mapping->len = rsc->len;
604 list_add_tail(&mapping->node, &rproc->mappings); 633 list_add_tail(&mapping->node, &rproc->mappings);
605 634
606 dev_dbg(dev, "carveout mapped 0x%x to 0x%x\n", rsc->da, dma); 635 dev_dbg(dev, "carveout mapped 0x%x to 0x%llx\n",
636 rsc->da, (unsigned long long)dma);
607 } 637 }
608 638
609 /* 639 /*
@@ -634,12 +664,12 @@ static int rproc_handle_carveout(struct rproc *rproc,
634 664
635 return 0; 665 return 0;
636 666
667free_mapping:
668 kfree(mapping);
637dma_free: 669dma_free:
638 dma_free_coherent(dev->parent, rsc->len, va, dma); 670 dma_free_coherent(dev->parent, rsc->len, va, dma);
639free_carv: 671free_carv:
640 kfree(carveout); 672 kfree(carveout);
641free_mapping:
642 kfree(mapping);
643 return ret; 673 return ret;
644} 674}
645 675
@@ -871,6 +901,91 @@ out:
871 complete_all(&rproc->firmware_loading_complete); 901 complete_all(&rproc->firmware_loading_complete);
872} 902}
873 903
904static int rproc_add_virtio_devices(struct rproc *rproc)
905{
906 int ret;
907
908 /* rproc_del() calls must wait until async loader completes */
909 init_completion(&rproc->firmware_loading_complete);
910
911 /*
912 * We must retrieve early virtio configuration info from
913 * the firmware (e.g. whether to register a virtio device,
914 * what virtio features does it support, ...).
915 *
916 * We're initiating an asynchronous firmware loading, so we can
917 * be built-in kernel code, without hanging the boot process.
918 */
919 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
920 rproc->firmware, &rproc->dev, GFP_KERNEL,
921 rproc, rproc_fw_config_virtio);
922 if (ret < 0) {
923 dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret);
924 complete_all(&rproc->firmware_loading_complete);
925 }
926
927 return ret;
928}
929
930/**
931 * rproc_trigger_recovery() - recover a remoteproc
932 * @rproc: the remote processor
933 *
934 * The recovery is done by reseting all the virtio devices, that way all the
935 * rpmsg drivers will be reseted along with the remote processor making the
936 * remoteproc functional again.
937 *
938 * This function can sleep, so it cannot be called from atomic context.
939 */
940int rproc_trigger_recovery(struct rproc *rproc)
941{
942 struct rproc_vdev *rvdev, *rvtmp;
943
944 dev_err(&rproc->dev, "recovering %s\n", rproc->name);
945
946 init_completion(&rproc->crash_comp);
947
948 /* clean up remote vdev entries */
949 list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
950 rproc_remove_virtio_dev(rvdev);
951
952 /* wait until there is no more rproc users */
953 wait_for_completion(&rproc->crash_comp);
954
955 return rproc_add_virtio_devices(rproc);
956}
957
958/**
959 * rproc_crash_handler_work() - handle a crash
960 *
961 * This function needs to handle everything related to a crash, like cpu
962 * registers and stack dump, information to help to debug the fatal error, etc.
963 */
964static void rproc_crash_handler_work(struct work_struct *work)
965{
966 struct rproc *rproc = container_of(work, struct rproc, crash_handler);
967 struct device *dev = &rproc->dev;
968
969 dev_dbg(dev, "enter %s\n", __func__);
970
971 mutex_lock(&rproc->lock);
972
973 if (rproc->state == RPROC_CRASHED || rproc->state == RPROC_OFFLINE) {
974 /* handle only the first crash detected */
975 mutex_unlock(&rproc->lock);
976 return;
977 }
978
979 rproc->state = RPROC_CRASHED;
980 dev_err(dev, "handling crash #%u in %s\n", ++rproc->crash_cnt,
981 rproc->name);
982
983 mutex_unlock(&rproc->lock);
984
985 if (!rproc->recovery_disabled)
986 rproc_trigger_recovery(rproc);
987}
988
874/** 989/**
875 * rproc_boot() - boot a remote processor 990 * rproc_boot() - boot a remote processor
876 * @rproc: handle of a remote processor 991 * @rproc: handle of a remote processor
@@ -992,6 +1107,10 @@ void rproc_shutdown(struct rproc *rproc)
992 1107
993 rproc_disable_iommu(rproc); 1108 rproc_disable_iommu(rproc);
994 1109
1110 /* if in crash state, unlock crash handler */
1111 if (rproc->state == RPROC_CRASHED)
1112 complete_all(&rproc->crash_comp);
1113
995 rproc->state = RPROC_OFFLINE; 1114 rproc->state = RPROC_OFFLINE;
996 1115
997 dev_info(dev, "stopped remote processor %s\n", rproc->name); 1116 dev_info(dev, "stopped remote processor %s\n", rproc->name);
@@ -1026,7 +1145,7 @@ EXPORT_SYMBOL(rproc_shutdown);
1026int rproc_add(struct rproc *rproc) 1145int rproc_add(struct rproc *rproc)
1027{ 1146{
1028 struct device *dev = &rproc->dev; 1147 struct device *dev = &rproc->dev;
1029 int ret = 0; 1148 int ret;
1030 1149
1031 ret = device_add(dev); 1150 ret = device_add(dev);
1032 if (ret < 0) 1151 if (ret < 0)
@@ -1040,26 +1159,7 @@ int rproc_add(struct rproc *rproc)
1040 /* create debugfs entries */ 1159 /* create debugfs entries */
1041 rproc_create_debug_dir(rproc); 1160 rproc_create_debug_dir(rproc);
1042 1161
1043 /* rproc_del() calls must wait until async loader completes */ 1162 return rproc_add_virtio_devices(rproc);
1044 init_completion(&rproc->firmware_loading_complete);
1045
1046 /*
1047 * We must retrieve early virtio configuration info from
1048 * the firmware (e.g. whether to register a virtio device,
1049 * what virtio features does it support, ...).
1050 *
1051 * We're initiating an asynchronous firmware loading, so we can
1052 * be built-in kernel code, without hanging the boot process.
1053 */
1054 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
1055 rproc->firmware, dev, GFP_KERNEL,
1056 rproc, rproc_fw_config_virtio);
1057 if (ret < 0) {
1058 dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
1059 complete_all(&rproc->firmware_loading_complete);
1060 }
1061
1062 return ret;
1063} 1163}
1064EXPORT_SYMBOL(rproc_add); 1164EXPORT_SYMBOL(rproc_add);
1065 1165
@@ -1165,6 +1265,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1165 INIT_LIST_HEAD(&rproc->traces); 1265 INIT_LIST_HEAD(&rproc->traces);
1166 INIT_LIST_HEAD(&rproc->rvdevs); 1266 INIT_LIST_HEAD(&rproc->rvdevs);
1167 1267
1268 INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
1269 init_completion(&rproc->crash_comp);
1270
1168 rproc->state = RPROC_OFFLINE; 1271 rproc->state = RPROC_OFFLINE;
1169 1272
1170 return rproc; 1273 return rproc;
@@ -1221,6 +1324,32 @@ int rproc_del(struct rproc *rproc)
1221} 1324}
1222EXPORT_SYMBOL(rproc_del); 1325EXPORT_SYMBOL(rproc_del);
1223 1326
1327/**
1328 * rproc_report_crash() - rproc crash reporter function
1329 * @rproc: remote processor
1330 * @type: crash type
1331 *
1332 * This function must be called every time a crash is detected by the low-level
1333 * drivers implementing a specific remoteproc. This should not be called from a
1334 * non-remoteproc driver.
1335 *
1336 * This function can be called from atomic/interrupt context.
1337 */
1338void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
1339{
1340 if (!rproc) {
1341 pr_err("NULL rproc pointer\n");
1342 return;
1343 }
1344
1345 dev_err(&rproc->dev, "crash detected in %s: type %s\n",
1346 rproc->name, rproc_crash_to_string(type));
1347
1348 /* create a new task to handle the error */
1349 schedule_work(&rproc->crash_handler);
1350}
1351EXPORT_SYMBOL(rproc_report_crash);
1352
1224static int __init remoteproc_init(void) 1353static int __init remoteproc_init(void)
1225{ 1354{
1226 rproc_init_debugfs(); 1355 rproc_init_debugfs();
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 03833850f214..157a57309601 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -28,6 +28,9 @@
28#include <linux/debugfs.h> 28#include <linux/debugfs.h>
29#include <linux/remoteproc.h> 29#include <linux/remoteproc.h>
30#include <linux/device.h> 30#include <linux/device.h>
31#include <linux/uaccess.h>
32
33#include "remoteproc_internal.h"
31 34
32/* remoteproc debugfs parent dir */ 35/* remoteproc debugfs parent dir */
33static struct dentry *rproc_dbg; 36static struct dentry *rproc_dbg;
@@ -79,7 +82,7 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
79 82
80 state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; 83 state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
81 84
82 i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], 85 i = scnprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state],
83 rproc->state); 86 rproc->state);
84 87
85 return simple_read_from_buffer(userbuf, count, ppos, buf, i); 88 return simple_read_from_buffer(userbuf, count, ppos, buf, i);
@@ -100,7 +103,7 @@ static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
100 char buf[100]; 103 char buf[100];
101 int i; 104 int i;
102 105
103 i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name); 106 i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
104 107
105 return simple_read_from_buffer(userbuf, count, ppos, buf, i); 108 return simple_read_from_buffer(userbuf, count, ppos, buf, i);
106} 109}
@@ -111,6 +114,82 @@ static const struct file_operations rproc_name_ops = {
111 .llseek = generic_file_llseek, 114 .llseek = generic_file_llseek,
112}; 115};
113 116
117/* expose recovery flag via debugfs */
118static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf,
119 size_t count, loff_t *ppos)
120{
121 struct rproc *rproc = filp->private_data;
122 char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n";
123
124 return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
125}
126
127/*
128 * By writing to the 'recovery' debugfs entry, we control the behavior of the
129 * recovery mechanism dynamically. The default value of this entry is "enabled".
130 *
131 * The 'recovery' debugfs entry supports these commands:
132 *
133 * enabled: When enabled, the remote processor will be automatically
134 * recovered whenever it crashes. Moreover, if the remote
135 * processor crashes while recovery is disabled, it will
136 * be automatically recovered too as soon as recovery is enabled.
137 *
138 * disabled: When disabled, a remote processor will remain in a crashed
139 * state if it crashes. This is useful for debugging purposes;
140 * without it, debugging a crash is substantially harder.
141 *
142 * recover: This function will trigger an immediate recovery if the
143 * remote processor is in a crashed state, without changing
144 * or checking the recovery state (enabled/disabled).
145 * This is useful during debugging sessions, when one expects
146 * additional crashes to happen after enabling recovery. In this
147 * case, enabling recovery will make it hard to debug subsequent
148 * crashes, so it's recommended to keep recovery disabled, and
149 * instead use the "recover" command as needed.
150 */
151static ssize_t
152rproc_recovery_write(struct file *filp, const char __user *user_buf,
153 size_t count, loff_t *ppos)
154{
155 struct rproc *rproc = filp->private_data;
156 char buf[10];
157 int ret;
158
159 if (count > sizeof(buf))
160 return count;
161
162 ret = copy_from_user(buf, user_buf, count);
163 if (ret)
164 return -EFAULT;
165
166 /* remove end of line */
167 if (buf[count - 1] == '\n')
168 buf[count - 1] = '\0';
169
170 if (!strncmp(buf, "enabled", count)) {
171 rproc->recovery_disabled = false;
172 /* if rproc has crashed, trigger recovery */
173 if (rproc->state == RPROC_CRASHED)
174 rproc_trigger_recovery(rproc);
175 } else if (!strncmp(buf, "disabled", count)) {
176 rproc->recovery_disabled = true;
177 } else if (!strncmp(buf, "recover", count)) {
178 /* if rproc has crashed, trigger recovery */
179 if (rproc->state == RPROC_CRASHED)
180 rproc_trigger_recovery(rproc);
181 }
182
183 return count;
184}
185
186static const struct file_operations rproc_recovery_ops = {
187 .read = rproc_recovery_read,
188 .write = rproc_recovery_write,
189 .open = simple_open,
190 .llseek = generic_file_llseek,
191};
192
114void rproc_remove_trace_file(struct dentry *tfile) 193void rproc_remove_trace_file(struct dentry *tfile)
115{ 194{
116 debugfs_remove(tfile); 195 debugfs_remove(tfile);
@@ -154,6 +233,8 @@ void rproc_create_debug_dir(struct rproc *rproc)
154 rproc, &rproc_name_ops); 233 rproc, &rproc_name_ops);
155 debugfs_create_file("state", 0400, rproc->dbg_dir, 234 debugfs_create_file("state", 0400, rproc->dbg_dir,
156 rproc, &rproc_state_ops); 235 rproc, &rproc_state_ops);
236 debugfs_create_file("recovery", 0400, rproc->dbg_dir,
237 rproc, &rproc_recovery_ops);
157} 238}
158 239
159void __init rproc_init_debugfs(void) 240void __init rproc_init_debugfs(void)
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/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c
new file mode 100644
index 000000000000..a7743c069339
--- /dev/null
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -0,0 +1,322 @@
1/*
2 * Copyright (C) ST-Ericsson AB 2012
3 * Author: Sjur Brændeland <sjur.brandeland@stericsson.com>
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/module.h>
8#include <linux/dma-mapping.h>
9#include <linux/remoteproc.h>
10#include <linux/ste_modem_shm.h>
11#include "remoteproc_internal.h"
12
13#define SPROC_FW_SIZE (50 * 4096)
14#define SPROC_MAX_TOC_ENTRIES 32
15#define SPROC_MAX_NOTIFY_ID 14
16#define SPROC_RESOURCE_NAME "rsc-table"
17#define SPROC_MODEM_NAME "ste-modem"
18#define SPROC_MODEM_FIRMWARE SPROC_MODEM_NAME "-fw.bin"
19
20#define sproc_dbg(sproc, fmt, ...) \
21 dev_dbg(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
22#define sproc_err(sproc, fmt, ...) \
23 dev_err(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
24
25/* STE-modem control structure */
26struct sproc {
27 struct rproc *rproc;
28 struct ste_modem_device *mdev;
29 int error;
30 void *fw_addr;
31 size_t fw_size;
32 dma_addr_t fw_dma_addr;
33};
34
35/* STE-Modem firmware entry */
36struct ste_toc_entry {
37 __le32 start;
38 __le32 size;
39 __le32 flags;
40 __le32 entry_point;
41 __le32 load_addr;
42 char name[12];
43};
44
45/*
46 * The Table Of Content is located at the start of the firmware image and
47 * at offset zero in the shared memory region. The resource table typically
48 * contains the initial boot image (boot strap) and other information elements
49 * such as remoteproc resource table. Each entry is identified by a unique
50 * name.
51 */
52struct ste_toc {
53 struct ste_toc_entry table[SPROC_MAX_TOC_ENTRIES];
54};
55
56/* Loads the firmware to shared memory. */
57static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
58{
59 struct sproc *sproc = rproc->priv;
60
61 memcpy(sproc->fw_addr, fw->data, fw->size);
62
63 return 0;
64}
65
66/* Find the entry for resource table in the Table of Content */
67static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
68{
69 int i;
70 struct ste_toc *toc;
71
72 if (!fw)
73 return NULL;
74
75 toc = (void *)fw->data;
76
77 /* Search the table for the resource table */
78 for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
79 toc->table[i].start != 0xffffffff; i++) {
80
81 if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
82 sizeof(toc->table[i].name))) {
83 if (toc->table[i].start > fw->size)
84 return NULL;
85 return &toc->table[i];
86 }
87 }
88
89 return NULL;
90}
91
92/* Find the resource table inside the remote processor's firmware. */
93static struct resource_table *
94sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
95 int *tablesz)
96{
97 struct sproc *sproc = rproc->priv;
98 struct resource_table *table;
99 struct ste_toc_entry *entry;
100
101 entry = sproc_find_rsc_entry(fw);
102 if (!entry) {
103 sproc_err(sproc, "resource table not found in fw\n");
104 return NULL;
105 }
106
107 table = (void *)(fw->data + entry->start);
108
109 /* sanity check size and offset of resource table */
110 if (entry->start > SPROC_FW_SIZE ||
111 entry->size > SPROC_FW_SIZE ||
112 fw->size > SPROC_FW_SIZE ||
113 entry->start + entry->size > fw->size ||
114 sizeof(struct resource_table) > entry->size) {
115 sproc_err(sproc, "bad size of fw or resource table\n");
116 return NULL;
117 }
118
119 /* we don't support any version beyond the first */
120 if (table->ver != 1) {
121 sproc_err(sproc, "unsupported fw ver: %d\n", table->ver);
122 return NULL;
123 }
124
125 /* make sure reserved bytes are zeroes */
126 if (table->reserved[0] || table->reserved[1]) {
127 sproc_err(sproc, "non zero reserved bytes\n");
128 return NULL;
129 }
130
131 /* make sure the offsets array isn't truncated */
132 if (table->num > SPROC_MAX_TOC_ENTRIES ||
133 table->num * sizeof(table->offset[0]) +
134 sizeof(struct resource_table) > entry->size) {
135 sproc_err(sproc, "resource table incomplete\n");
136 return NULL;
137 }
138
139 /* If the fw size has grown, release the previous fw allocation */
140 if (SPROC_FW_SIZE < fw->size) {
141 sproc_err(sproc, "Insufficient space for fw (%d < %zd)\n",
142 SPROC_FW_SIZE, fw->size);
143 return NULL;
144 }
145
146 sproc->fw_size = fw->size;
147 *tablesz = entry->size;
148
149 return table;
150}
151
152/* STE modem firmware handler operations */
153const struct rproc_fw_ops sproc_fw_ops = {
154 .load = sproc_load_segments,
155 .find_rsc_table = sproc_find_rsc_table,
156};
157
158/* Kick the modem with specified notification id */
159static void sproc_kick(struct rproc *rproc, int vqid)
160{
161 struct sproc *sproc = rproc->priv;
162
163 sproc_dbg(sproc, "kick vqid:%d\n", vqid);
164
165 /*
166 * We need different notification IDs for RX and TX so add
167 * an offset on TX notification IDs.
168 */
169 sproc->mdev->ops.kick(sproc->mdev, vqid + SPROC_MAX_NOTIFY_ID);
170}
171
172/* Received a kick from a modem, kick the virtqueue */
173static void sproc_kick_callback(struct ste_modem_device *mdev, int vqid)
174{
175 struct sproc *sproc = mdev->drv_data;
176
177 if (rproc_vq_interrupt(sproc->rproc, vqid) == IRQ_NONE)
178 sproc_dbg(sproc, "no message was found in vqid %d\n", vqid);
179}
180
181struct ste_modem_dev_cb sproc_dev_cb = {
182 .kick = sproc_kick_callback,
183};
184
185/* Start the STE modem */
186static int sproc_start(struct rproc *rproc)
187{
188 struct sproc *sproc = rproc->priv;
189 int i, err;
190
191 sproc_dbg(sproc, "start ste-modem\n");
192
193 /* Sanity test the max_notifyid */
194 if (rproc->max_notifyid > SPROC_MAX_NOTIFY_ID) {
195 sproc_err(sproc, "Notification IDs too high:%d\n",
196 rproc->max_notifyid);
197 return -EINVAL;
198 }
199
200 /* Subscribe to notifications */
201 for (i = 0; i < rproc->max_notifyid; i++) {
202 err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i);
203 if (err) {
204 sproc_err(sproc,
205 "subscription of kicks failed:%d\n", err);
206 return err;
207 }
208 }
209
210 /* Request modem start-up*/
211 return sproc->mdev->ops.power(sproc->mdev, true);
212}
213
214/* Stop the STE modem */
215static int sproc_stop(struct rproc *rproc)
216{
217 struct sproc *sproc = rproc->priv;
218 sproc_dbg(sproc, "stop ste-modem\n");
219
220 return sproc->mdev->ops.power(sproc->mdev, false);
221}
222
223static struct rproc_ops sproc_ops = {
224 .start = sproc_start,
225 .stop = sproc_stop,
226 .kick = sproc_kick,
227};
228
229/* STE modem device is unregistered */
230static int sproc_drv_remove(struct platform_device *pdev)
231{
232 struct ste_modem_device *mdev =
233 container_of(pdev, struct ste_modem_device, pdev);
234 struct sproc *sproc = mdev->drv_data;
235
236 sproc_dbg(sproc, "remove ste-modem\n");
237
238 /* Reset device callback functions */
239 sproc->mdev->ops.setup(sproc->mdev, NULL);
240
241 /* Unregister as remoteproc device */
242 rproc_del(sproc->rproc);
243 rproc_put(sproc->rproc);
244
245 mdev->drv_data = NULL;
246
247 return 0;
248}
249
250/* Handle probe of a modem device */
251static int sproc_probe(struct platform_device *pdev)
252{
253 struct ste_modem_device *mdev =
254 container_of(pdev, struct ste_modem_device, pdev);
255 struct sproc *sproc;
256 struct rproc *rproc;
257 int err;
258
259 dev_dbg(&mdev->pdev.dev, "probe ste-modem\n");
260
261 if (!mdev->ops.setup || !mdev->ops.kick || !mdev->ops.kick_subscribe ||
262 !mdev->ops.power) {
263 dev_err(&mdev->pdev.dev, "invalid mdev ops\n");
264 return -EINVAL;
265 }
266
267 rproc = rproc_alloc(&mdev->pdev.dev, mdev->pdev.name, &sproc_ops,
268 SPROC_MODEM_FIRMWARE, sizeof(*sproc));
269 if (!rproc)
270 return -ENOMEM;
271
272 sproc = rproc->priv;
273 sproc->mdev = mdev;
274 sproc->rproc = rproc;
275 mdev->drv_data = sproc;
276
277 /* Provide callback functions to modem device */
278 sproc->mdev->ops.setup(sproc->mdev, &sproc_dev_cb);
279
280 /* Set the STE-modem specific firmware handler */
281 rproc->fw_ops = &sproc_fw_ops;
282
283 /*
284 * STE-modem requires the firmware to be located
285 * at the start of the shared memory region. So we need to
286 * reserve space for firmware at the start.
287 */
288 sproc->fw_addr = dma_alloc_coherent(rproc->dev.parent, SPROC_FW_SIZE,
289 &sproc->fw_dma_addr,
290 GFP_KERNEL);
291 if (!sproc->fw_addr) {
292 sproc_err(sproc, "Cannot allocate memory for fw\n");
293 err = -ENOMEM;
294 goto free_rproc;
295 }
296
297 /* Register as a remoteproc device */
298 err = rproc_add(rproc);
299 if (err)
300 goto free_rproc;
301
302 return 0;
303
304free_rproc:
305 /* Reset device data upon error */
306 mdev->drv_data = NULL;
307 rproc_put(rproc);
308 return err;
309}
310
311static struct platform_driver sproc_driver = {
312 .driver = {
313 .name = SPROC_MODEM_NAME,
314 .owner = THIS_MODULE,
315 },
316 .probe = sproc_probe,
317 .remove = sproc_drv_remove,
318};
319
320module_platform_driver(sproc_driver);
321MODULE_LICENSE("GPL v2");
322MODULE_DESCRIPTION("STE Modem driver using the Remote Processor Framework");