aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 17:04:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 17:04:56 -0400
commitde9c9f86be0dc3495de98dc65c80abe6e7c7d643 (patch)
tree47ad4787412b26eea9f49b858855f919b0cb4898
parent3e11a00d8561622a2598254853e2e8cc3e51e544 (diff)
parentb9777859ec015a78dae1476e317d04f851bfdd0d (diff)
Merge tag 'remoteproc-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc
Pull remoteproc update from Ohad Ben-Cohen: - Some refactoring, cleanups and small improvements from Sjur Brændeland. The improvements are mainly about better supporting varios virtio properties (such as virtio's config space, status and features). I now see that I messed up while commiting one of Sjur's patches and erroneously put myself as the author, as well as letting a nasty typo sneak in. I will not fix this in order to avoid rebasing the patches. Sjur - sorry! - A new remoteproc driver for OMAP-L13x (technically a DaVinci platform) from Robert Tivy. - Extend OMAP support to OMAP5 as well, from Vincent Stehlé. - Fix Kconfig VIRTUALIZATION dependency, from Suman Anna (a non-critical fix which arrived late during the rc cycle). * tag 'remoteproc-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc: remoteproc: fix kconfig dependencies for VIRTIO remoteproc/davinci: add a remoteproc driver for OMAP-L13x DSP remoteproc: support default firmware name in rproc_alloc() remoteproc/omap: support OMAP5 too remoteproc: set vring addresses in resource table remoteproc: support virtio config space. remoteproc: perserve resource table data remoteproc: calculate max_notifyid by counting vrings remoteproc: code cleanup of resource parsing remoteproc: parse STE-firmware and find resource table address remoteproc: add find_loaded_rsc_table firmware ops remoteproc: refactor rproc_elf_find_rsc_table()
-rw-r--r--drivers/remoteproc/Kconfig27
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c324
-rw-r--r--drivers/remoteproc/remoteproc_core.c211
-rw-r--r--drivers/remoteproc/remoteproc_elf_loader.c100
-rw-r--r--drivers/remoteproc/remoteproc_internal.h15
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c79
-rw-r--r--drivers/remoteproc/ste_modem_rproc.c45
-rw-r--r--include/linux/remoteproc.h13
9 files changed, 677 insertions, 138 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index c6d77e20622c..d4d377c40ec9 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -4,13 +4,15 @@ menu "Remoteproc drivers"
4config REMOTEPROC 4config REMOTEPROC
5 tristate 5 tristate
6 depends on HAS_DMA 6 depends on HAS_DMA
7 select CRC32
7 select FW_LOADER 8 select FW_LOADER
8 select VIRTIO 9 select VIRTIO
10 select VIRTUALIZATION
9 11
10config OMAP_REMOTEPROC 12config OMAP_REMOTEPROC
11 tristate "OMAP remoteproc support" 13 tristate "OMAP remoteproc support"
12 depends on HAS_DMA 14 depends on HAS_DMA
13 depends on ARCH_OMAP4 15 depends on ARCH_OMAP4 || SOC_OMAP5
14 depends on OMAP_IOMMU 16 depends on OMAP_IOMMU
15 depends on OMAP_MBOX_FWK 17 depends on OMAP_MBOX_FWK
16 select REMOTEPROC 18 select REMOTEPROC
@@ -38,4 +40,27 @@ config STE_MODEM_RPROC
38 This can be either built-in or a loadable module. 40 This can be either built-in or a loadable module.
39 If unsure say N. 41 If unsure say N.
40 42
43config DA8XX_REMOTEPROC
44 tristate "DA8xx/OMAP-L13x remoteproc support"
45 depends on ARCH_DAVINCI_DA8XX
46 select CMA
47 select REMOTEPROC
48 select RPMSG
49 help
50 Say y here to support DA8xx/OMAP-L13x remote processors via the
51 remote processor framework.
52
53 You want to say y here in order to enable AMP
54 use-cases to run on your platform (multimedia codecs are
55 offloaded to remote DSP processors using this framework).
56
57 This module controls the name of the firmware file that gets
58 loaded on the DSP. This file must reside in the /lib/firmware
59 directory. It can be specified via the module parameter
60 da8xx_fw_name=<filename>, and if not specified will default to
61 "rproc-dsp-fw".
62
63 It's safe to say n here if you're not interested in multimedia
64 offloading.
65
41endmenu 66endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 391b65181c05..ac2ff75686d2 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -9,3 +9,4 @@ remoteproc-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 11obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
12obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
new file mode 100644
index 000000000000..9b2e60afa1a6
--- /dev/null
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -0,0 +1,324 @@
1/*
2 * Remote processor machine-specific module for DA8XX
3 *
4 * Copyright (C) 2013 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 */
10
11#include <linux/bitops.h>
12#include <linux/clk.h>
13#include <linux/err.h>
14#include <linux/interrupt.h>
15#include <linux/io.h>
16#include <linux/irq.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/remoteproc.h>
21
22#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */
23
24#include "remoteproc_internal.h"
25
26static char *da8xx_fw_name;
27module_param(da8xx_fw_name, charp, S_IRUGO);
28MODULE_PARM_DESC(da8xx_fw_name,
29 "\n\t\tName of DSP firmware file in /lib/firmware"
30 " (if not specified defaults to 'rproc-dsp-fw')");
31
32/*
33 * OMAP-L138 Technical References:
34 * http://www.ti.com/product/omap-l138
35 */
36#define SYSCFG_CHIPSIG0 BIT(0)
37#define SYSCFG_CHIPSIG1 BIT(1)
38#define SYSCFG_CHIPSIG2 BIT(2)
39#define SYSCFG_CHIPSIG3 BIT(3)
40#define SYSCFG_CHIPSIG4 BIT(4)
41
42/**
43 * struct da8xx_rproc - da8xx remote processor instance state
44 * @rproc: rproc handle
45 * @dsp_clk: placeholder for platform's DSP clk
46 * @ack_fxn: chip-specific ack function for ack'ing irq
47 * @irq_data: ack_fxn function parameter
48 * @chipsig: virt ptr to DSP interrupt registers (CHIPSIG & CHIPSIG_CLR)
49 * @bootreg: virt ptr to DSP boot address register (HOST1CFG)
50 * @irq: irq # used by this instance
51 */
52struct da8xx_rproc {
53 struct rproc *rproc;
54 struct clk *dsp_clk;
55 void (*ack_fxn)(struct irq_data *data);
56 struct irq_data *irq_data;
57 void __iomem *chipsig;
58 void __iomem *bootreg;
59 int irq;
60};
61
62/**
63 * handle_event() - inbound virtqueue message workqueue function
64 *
65 * This function is registered as a kernel thread and is scheduled by the
66 * kernel handler.
67 */
68static irqreturn_t handle_event(int irq, void *p)
69{
70 struct rproc *rproc = (struct rproc *)p;
71
72 /* Process incoming buffers on all our vrings */
73 rproc_vq_interrupt(rproc, 0);
74 rproc_vq_interrupt(rproc, 1);
75
76 return IRQ_HANDLED;
77}
78
79/**
80 * da8xx_rproc_callback() - inbound virtqueue message handler
81 *
82 * This handler is invoked directly by the kernel whenever the remote
83 * core (DSP) has modified the state of a virtqueue. There is no
84 * "payload" message indicating the virtqueue index as is the case with
85 * mailbox-based implementations on OMAP4. As such, this handler "polls"
86 * each known virtqueue index for every invocation.
87 */
88static irqreturn_t da8xx_rproc_callback(int irq, void *p)
89{
90 struct rproc *rproc = (struct rproc *)p;
91 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
92 u32 chipsig;
93
94 chipsig = readl(drproc->chipsig);
95 if (chipsig & SYSCFG_CHIPSIG0) {
96 /* Clear interrupt level source */
97 writel(SYSCFG_CHIPSIG0, drproc->chipsig + 4);
98
99 /*
100 * ACK intr to AINTC.
101 *
102 * It has already been ack'ed by the kernel before calling
103 * this function, but since the ARM<->DSP interrupts in the
104 * CHIPSIG register are "level" instead of "pulse" variety,
105 * we need to ack it after taking down the level else we'll
106 * be called again immediately after returning.
107 */
108 drproc->ack_fxn(drproc->irq_data);
109
110 return IRQ_WAKE_THREAD;
111 }
112
113 return IRQ_HANDLED;
114}
115
116static int da8xx_rproc_start(struct rproc *rproc)
117{
118 struct device *dev = rproc->dev.parent;
119 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
120 struct clk *dsp_clk = drproc->dsp_clk;
121
122 /* hw requires the start (boot) address be on 1KB boundary */
123 if (rproc->bootaddr & 0x3ff) {
124 dev_err(dev, "invalid boot address: must be aligned to 1KB\n");
125
126 return -EINVAL;
127 }
128
129 writel(rproc->bootaddr, drproc->bootreg);
130
131 clk_enable(dsp_clk);
132 davinci_clk_reset_deassert(dsp_clk);
133
134 return 0;
135}
136
137static int da8xx_rproc_stop(struct rproc *rproc)
138{
139 struct da8xx_rproc *drproc = rproc->priv;
140
141 clk_disable(drproc->dsp_clk);
142
143 return 0;
144}
145
146/* kick a virtqueue */
147static void da8xx_rproc_kick(struct rproc *rproc, int vqid)
148{
149 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
150
151 /* Interupt remote proc */
152 writel(SYSCFG_CHIPSIG2, drproc->chipsig);
153}
154
155static struct rproc_ops da8xx_rproc_ops = {
156 .start = da8xx_rproc_start,
157 .stop = da8xx_rproc_stop,
158 .kick = da8xx_rproc_kick,
159};
160
161static int reset_assert(struct device *dev)
162{
163 struct clk *dsp_clk;
164
165 dsp_clk = clk_get(dev, NULL);
166 if (IS_ERR(dsp_clk)) {
167 dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk));
168 return PTR_RET(dsp_clk);
169 }
170
171 davinci_clk_reset_assert(dsp_clk);
172 clk_put(dsp_clk);
173
174 return 0;
175}
176
177static int da8xx_rproc_probe(struct platform_device *pdev)
178{
179 struct device *dev = &pdev->dev;
180 struct da8xx_rproc *drproc;
181 struct rproc *rproc;
182 struct irq_data *irq_data;
183 struct resource *bootreg_res;
184 struct resource *chipsig_res;
185 struct clk *dsp_clk;
186 void __iomem *chipsig;
187 void __iomem *bootreg;
188 int irq;
189 int ret;
190
191 irq = platform_get_irq(pdev, 0);
192 if (irq < 0) {
193 dev_err(dev, "platform_get_irq(pdev, 0) error: %d\n", irq);
194 return irq;
195 }
196
197 irq_data = irq_get_irq_data(irq);
198 if (!irq_data) {
199 dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq);
200 return -EINVAL;
201 }
202
203 bootreg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
204 if (!bootreg_res) {
205 dev_err(dev,
206 "platform_get_resource(IORESOURCE_MEM, 0): NULL\n");
207 return -EADDRNOTAVAIL;
208 }
209
210 chipsig_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
211 if (!chipsig_res) {
212 dev_err(dev,
213 "platform_get_resource(IORESOURCE_MEM, 1): NULL\n");
214 return -EADDRNOTAVAIL;
215 }
216
217 bootreg = devm_ioremap_resource(dev, bootreg_res);
218 if (IS_ERR(bootreg))
219 return PTR_ERR(bootreg);
220
221 chipsig = devm_ioremap_resource(dev, chipsig_res);
222 if (IS_ERR(chipsig))
223 return PTR_ERR(chipsig);
224
225 dsp_clk = devm_clk_get(dev, NULL);
226 if (IS_ERR(dsp_clk)) {
227 dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk));
228
229 return PTR_ERR(dsp_clk);
230 }
231
232 rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name,
233 sizeof(*drproc));
234 if (!rproc)
235 return -ENOMEM;
236
237 drproc = rproc->priv;
238 drproc->rproc = rproc;
239
240 platform_set_drvdata(pdev, rproc);
241
242 /* everything the ISR needs is now setup, so hook it up */
243 ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback,
244 handle_event, 0, "da8xx-remoteproc",
245 rproc);
246 if (ret) {
247 dev_err(dev, "devm_request_threaded_irq error: %d\n", ret);
248 goto free_rproc;
249 }
250
251 /*
252 * rproc_add() can end up enabling the DSP's clk with the DSP
253 * *not* in reset, but da8xx_rproc_start() needs the DSP to be
254 * held in reset at the time it is called.
255 */
256 ret = reset_assert(dev);
257 if (ret)
258 goto free_rproc;
259
260 drproc->chipsig = chipsig;
261 drproc->bootreg = bootreg;
262 drproc->ack_fxn = irq_data->chip->irq_ack;
263 drproc->irq_data = irq_data;
264 drproc->irq = irq;
265 drproc->dsp_clk = dsp_clk;
266
267 ret = rproc_add(rproc);
268 if (ret) {
269 dev_err(dev, "rproc_add failed: %d\n", ret);
270 goto free_rproc;
271 }
272
273 return 0;
274
275free_rproc:
276 rproc_put(rproc);
277
278 return ret;
279}
280
281static int da8xx_rproc_remove(struct platform_device *pdev)
282{
283 struct device *dev = &pdev->dev;
284 struct rproc *rproc = platform_get_drvdata(pdev);
285 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
286
287 /*
288 * It's important to place the DSP in reset before going away,
289 * since a subsequent insmod of this module may enable the DSP's
290 * clock before its program/boot-address has been loaded and
291 * before this module's probe has had a chance to reset the DSP.
292 * Without the reset, the DSP can lockup permanently when it
293 * begins executing garbage.
294 */
295 reset_assert(dev);
296
297 /*
298 * The devm subsystem might end up releasing things before
299 * freeing the irq, thus allowing an interrupt to sneak in while
300 * the device is being removed. This should prevent that.
301 */
302 disable_irq(drproc->irq);
303
304 devm_clk_put(dev, drproc->dsp_clk);
305
306 rproc_del(rproc);
307 rproc_put(rproc);
308
309 return 0;
310}
311
312static struct platform_driver da8xx_rproc_driver = {
313 .probe = da8xx_rproc_probe,
314 .remove = da8xx_rproc_remove,
315 .driver = {
316 .name = "davinci-rproc",
317 .owner = THIS_MODULE,
318 },
319};
320
321module_platform_driver(da8xx_rproc_driver);
322
323MODULE_LICENSE("GPL v2");
324MODULE_DESCRIPTION("DA8XX Remote Processor control driver");
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 814af5ab8a72..022dc635d01e 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -37,6 +37,7 @@
37#include <linux/iommu.h> 37#include <linux/iommu.h>
38#include <linux/idr.h> 38#include <linux/idr.h>
39#include <linux/elf.h> 39#include <linux/elf.h>
40#include <linux/crc32.h>
40#include <linux/virtio_ids.h> 41#include <linux/virtio_ids.h>
41#include <linux/virtio_ring.h> 42#include <linux/virtio_ring.h>
42#include <asm/byteorder.h> 43#include <asm/byteorder.h>
@@ -45,7 +46,8 @@
45 46
46typedef int (*rproc_handle_resources_t)(struct rproc *rproc, 47typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
47 struct resource_table *table, int len); 48 struct resource_table *table, int len);
48typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); 49typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
50 void *, int offset, int avail);
49 51
50/* Unique indices for remoteproc devices */ 52/* Unique indices for remoteproc devices */
51static DEFINE_IDA(rproc_dev_index); 53static DEFINE_IDA(rproc_dev_index);
@@ -192,6 +194,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
192 struct rproc *rproc = rvdev->rproc; 194 struct rproc *rproc = rvdev->rproc;
193 struct device *dev = &rproc->dev; 195 struct device *dev = &rproc->dev;
194 struct rproc_vring *rvring = &rvdev->vring[i]; 196 struct rproc_vring *rvring = &rvdev->vring[i];
197 struct fw_rsc_vdev *rsc;
195 dma_addr_t dma; 198 dma_addr_t dma;
196 void *va; 199 void *va;
197 int ret, size, notifyid; 200 int ret, size, notifyid;
@@ -202,7 +205,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
202 /* 205 /*
203 * Allocate non-cacheable memory for the vring. In the future 206 * Allocate non-cacheable memory for the vring. In the future
204 * this call will also configure the IOMMU for us 207 * this call will also configure the IOMMU for us
205 * TODO: let the rproc know the da of this vring
206 */ 208 */
207 va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL); 209 va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
208 if (!va) { 210 if (!va) {
@@ -213,7 +215,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
213 /* 215 /*
214 * Assign an rproc-wide unique index for this vring 216 * Assign an rproc-wide unique index for this vring
215 * TODO: assign a notifyid for rvdev updates as well 217 * TODO: assign a notifyid for rvdev updates as well
216 * TODO: let the rproc know the notifyid of this vring
217 * TODO: support predefined notifyids (via resource table) 218 * TODO: support predefined notifyids (via resource table)
218 */ 219 */
219 ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); 220 ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
@@ -224,9 +225,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
224 } 225 }
225 notifyid = ret; 226 notifyid = ret;
226 227
227 /* Store largest notifyid */
228 rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
229
230 dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va, 228 dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
231 (unsigned long long)dma, size, notifyid); 229 (unsigned long long)dma, size, notifyid);
232 230
@@ -234,6 +232,15 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
234 rvring->dma = dma; 232 rvring->dma = dma;
235 rvring->notifyid = notifyid; 233 rvring->notifyid = notifyid;
236 234
235 /*
236 * Let the rproc know the notifyid and da of this vring.
237 * Not all platforms use dma_alloc_coherent to automatically
238 * set up the iommu. In this case the device address (da) will
239 * hold the physical address and not the device address.
240 */
241 rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
242 rsc->vring[i].da = dma;
243 rsc->vring[i].notifyid = notifyid;
237 return 0; 244 return 0;
238} 245}
239 246
@@ -268,25 +275,20 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
268 return 0; 275 return 0;
269} 276}
270 277
271static int rproc_max_notifyid(int id, void *p, void *data)
272{
273 int *maxid = data;
274 *maxid = max(*maxid, id);
275 return 0;
276}
277
278void rproc_free_vring(struct rproc_vring *rvring) 278void rproc_free_vring(struct rproc_vring *rvring)
279{ 279{
280 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); 280 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
281 struct rproc *rproc = rvring->rvdev->rproc; 281 struct rproc *rproc = rvring->rvdev->rproc;
282 int maxid = 0; 282 int idx = rvring->rvdev->vring - rvring;
283 struct fw_rsc_vdev *rsc;
283 284
284 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); 285 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
285 idr_remove(&rproc->notifyids, rvring->notifyid); 286 idr_remove(&rproc->notifyids, rvring->notifyid);
286 287
287 /* Find the largest remaining notifyid */ 288 /* reset resource entry info */
288 idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid); 289 rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset;
289 rproc->max_notifyid = maxid; 290 rsc->vring[idx].da = 0;
291 rsc->vring[idx].notifyid = -1;
290} 292}
291 293
292/** 294/**
@@ -317,7 +319,7 @@ void rproc_free_vring(struct rproc_vring *rvring)
317 * Returns 0 on success, or an appropriate error code otherwise 319 * Returns 0 on success, or an appropriate error code otherwise
318 */ 320 */
319static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, 321static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
320 int avail) 322 int offset, int avail)
321{ 323{
322 struct device *dev = &rproc->dev; 324 struct device *dev = &rproc->dev;
323 struct rproc_vdev *rvdev; 325 struct rproc_vdev *rvdev;
@@ -358,8 +360,8 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
358 goto free_rvdev; 360 goto free_rvdev;
359 } 361 }
360 362
361 /* remember the device features */ 363 /* remember the resource offset*/
362 rvdev->dfeatures = rsc->dfeatures; 364 rvdev->rsc_offset = offset;
363 365
364 list_add_tail(&rvdev->node, &rproc->rvdevs); 366 list_add_tail(&rvdev->node, &rproc->rvdevs);
365 367
@@ -394,7 +396,7 @@ free_rvdev:
394 * Returns 0 on success, or an appropriate error code otherwise 396 * Returns 0 on success, or an appropriate error code otherwise
395 */ 397 */
396static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, 398static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
397 int avail) 399 int offset, int avail)
398{ 400{
399 struct rproc_mem_entry *trace; 401 struct rproc_mem_entry *trace;
400 struct device *dev = &rproc->dev; 402 struct device *dev = &rproc->dev;
@@ -476,7 +478,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
476 * are outside those ranges. 478 * are outside those ranges.
477 */ 479 */
478static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, 480static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
479 int avail) 481 int offset, int avail)
480{ 482{
481 struct rproc_mem_entry *mapping; 483 struct rproc_mem_entry *mapping;
482 struct device *dev = &rproc->dev; 484 struct device *dev = &rproc->dev;
@@ -549,7 +551,9 @@ out:
549 * pressure is important; it may have a substantial impact on performance. 551 * pressure is important; it may have a substantial impact on performance.
550 */ 552 */
551static int rproc_handle_carveout(struct rproc *rproc, 553static int rproc_handle_carveout(struct rproc *rproc,
552 struct fw_rsc_carveout *rsc, int avail) 554 struct fw_rsc_carveout *rsc,
555 int offset, int avail)
556
553{ 557{
554 struct rproc_mem_entry *carveout, *mapping; 558 struct rproc_mem_entry *carveout, *mapping;
555 struct device *dev = &rproc->dev; 559 struct device *dev = &rproc->dev;
@@ -671,28 +675,45 @@ free_carv:
671 return ret; 675 return ret;
672} 676}
673 677
678static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc,
679 int offset, int avail)
680{
681 /* Summarize the number of notification IDs */
682 rproc->max_notifyid += rsc->num_of_vrings;
683
684 return 0;
685}
686
674/* 687/*
675 * A lookup table for resource handlers. The indices are defined in 688 * A lookup table for resource handlers. The indices are defined in
676 * enum fw_resource_type. 689 * enum fw_resource_type.
677 */ 690 */
678static rproc_handle_resource_t rproc_handle_rsc[] = { 691static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
679 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, 692 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
680 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, 693 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
681 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, 694 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
682 [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */ 695 [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
683}; 696};
684 697
698static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = {
699 [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
700};
701
702static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = {
703 [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings,
704};
705
685/* handle firmware resource entries before booting the remote processor */ 706/* handle firmware resource entries before booting the remote processor */
686static int 707static int rproc_handle_resources(struct rproc *rproc, int len,
687rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len) 708 rproc_handle_resource_t handlers[RSC_LAST])
688{ 709{
689 struct device *dev = &rproc->dev; 710 struct device *dev = &rproc->dev;
690 rproc_handle_resource_t handler; 711 rproc_handle_resource_t handler;
691 int ret = 0, i; 712 int ret = 0, i;
692 713
693 for (i = 0; i < table->num; i++) { 714 for (i = 0; i < rproc->table_ptr->num; i++) {
694 int offset = table->offset[i]; 715 int offset = rproc->table_ptr->offset[i];
695 struct fw_rsc_hdr *hdr = (void *)table + offset; 716 struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
696 int avail = len - offset - sizeof(*hdr); 717 int avail = len - offset - sizeof(*hdr);
697 void *rsc = (void *)hdr + sizeof(*hdr); 718 void *rsc = (void *)hdr + sizeof(*hdr);
698 719
@@ -709,45 +730,11 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len
709 continue; 730 continue;
710 } 731 }
711 732
712 handler = rproc_handle_rsc[hdr->type]; 733 handler = handlers[hdr->type];
713 if (!handler) 734 if (!handler)
714 continue; 735 continue;
715 736
716 ret = handler(rproc, rsc, avail); 737 ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
717 if (ret)
718 break;
719 }
720
721 return ret;
722}
723
724/* handle firmware resource entries while registering the remote processor */
725static int
726rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len)
727{
728 struct device *dev = &rproc->dev;
729 int ret = 0, i;
730
731 for (i = 0; i < table->num; i++) {
732 int offset = table->offset[i];
733 struct fw_rsc_hdr *hdr = (void *)table + offset;
734 int avail = len - offset - sizeof(*hdr);
735 struct fw_rsc_vdev *vrsc;
736
737 /* make sure table isn't truncated */
738 if (avail < 0) {
739 dev_err(dev, "rsc table is truncated\n");
740 return -EINVAL;
741 }
742
743 dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
744
745 if (hdr->type != RSC_VDEV)
746 continue;
747
748 vrsc = (struct fw_rsc_vdev *)hdr->data;
749
750 ret = rproc_handle_vdev(rproc, vrsc, avail);
751 if (ret) 738 if (ret)
752 break; 739 break;
753 } 740 }
@@ -805,9 +792,12 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
805{ 792{
806 struct device *dev = &rproc->dev; 793 struct device *dev = &rproc->dev;
807 const char *name = rproc->firmware; 794 const char *name = rproc->firmware;
808 struct resource_table *table; 795 struct resource_table *table, *loaded_table;
809 int ret, tablesz; 796 int ret, tablesz;
810 797
798 if (!rproc->table_ptr)
799 return -ENOMEM;
800
811 ret = rproc_fw_sanity_check(rproc, fw); 801 ret = rproc_fw_sanity_check(rproc, fw);
812 if (ret) 802 if (ret)
813 return ret; 803 return ret;
@@ -833,8 +823,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
833 goto clean_up; 823 goto clean_up;
834 } 824 }
835 825
826 /* Verify that resource table in loaded fw is unchanged */
827 if (rproc->table_csum != crc32(0, table, tablesz)) {
828 dev_err(dev, "resource checksum failed, fw changed?\n");
829 ret = -EINVAL;
830 goto clean_up;
831 }
832
836 /* handle fw resources which are required to boot rproc */ 833 /* handle fw resources which are required to boot rproc */
837 ret = rproc_handle_boot_rsc(rproc, table, tablesz); 834 ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
838 if (ret) { 835 if (ret) {
839 dev_err(dev, "Failed to process resources: %d\n", ret); 836 dev_err(dev, "Failed to process resources: %d\n", ret);
840 goto clean_up; 837 goto clean_up;
@@ -847,6 +844,19 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
847 goto clean_up; 844 goto clean_up;
848 } 845 }
849 846
847 /*
848 * The starting device has been given the rproc->cached_table as the
849 * resource table. The address of the vring along with the other
850 * allocated resources (carveouts etc) is stored in cached_table.
851 * In order to pass this information to the remote device we must
852 * copy this information to device memory.
853 */
854 loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
855 if (!loaded_table)
856 goto clean_up;
857
858 memcpy(loaded_table, rproc->cached_table, tablesz);
859
850 /* power up the remote processor */ 860 /* power up the remote processor */
851 ret = rproc->ops->start(rproc); 861 ret = rproc->ops->start(rproc);
852 if (ret) { 862 if (ret) {
@@ -854,6 +864,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
854 goto clean_up; 864 goto clean_up;
855 } 865 }
856 866
867 /*
868 * Update table_ptr so that all subsequent vring allocations and
869 * virtio fields manipulation update the actual loaded resource table
870 * in device memory.
871 */
872 rproc->table_ptr = loaded_table;
873
857 rproc->state = RPROC_RUNNING; 874 rproc->state = RPROC_RUNNING;
858 875
859 dev_info(dev, "remote processor %s is now up\n", rproc->name); 876 dev_info(dev, "remote processor %s is now up\n", rproc->name);
@@ -888,11 +905,30 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
888 if (!table) 905 if (!table)
889 goto out; 906 goto out;
890 907
891 /* look for virtio devices and register them */ 908 rproc->table_csum = crc32(0, table, tablesz);
892 ret = rproc_handle_virtio_rsc(rproc, table, tablesz); 909
910 /*
911 * Create a copy of the resource table. When a virtio device starts
912 * and calls vring_new_virtqueue() the address of the allocated vring
913 * will be stored in the cached_table. Before the device is started,
914 * cached_table will be copied into devic memory.
915 */
916 rproc->cached_table = kmalloc(tablesz, GFP_KERNEL);
917 if (!rproc->cached_table)
918 goto out;
919
920 memcpy(rproc->cached_table, table, tablesz);
921 rproc->table_ptr = rproc->cached_table;
922
923 /* count the number of notify-ids */
924 rproc->max_notifyid = -1;
925 ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler);
893 if (ret) 926 if (ret)
894 goto out; 927 goto out;
895 928
929 /* look for virtio devices and register them */
930 ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
931
896out: 932out:
897 release_firmware(fw); 933 release_firmware(fw);
898 /* allow rproc_del() contexts, if any, to proceed */ 934 /* allow rproc_del() contexts, if any, to proceed */
@@ -950,6 +986,9 @@ int rproc_trigger_recovery(struct rproc *rproc)
950 /* wait until there is no more rproc users */ 986 /* wait until there is no more rproc users */
951 wait_for_completion(&rproc->crash_comp); 987 wait_for_completion(&rproc->crash_comp);
952 988
989 /* Free the copy of the resource table */
990 kfree(rproc->cached_table);
991
953 return rproc_add_virtio_devices(rproc); 992 return rproc_add_virtio_devices(rproc);
954} 993}
955 994
@@ -1105,6 +1144,9 @@ void rproc_shutdown(struct rproc *rproc)
1105 1144
1106 rproc_disable_iommu(rproc); 1145 rproc_disable_iommu(rproc);
1107 1146
1147 /* Give the next start a clean resource table */
1148 rproc->table_ptr = rproc->cached_table;
1149
1108 /* if in crash state, unlock crash handler */ 1150 /* if in crash state, unlock crash handler */
1109 if (rproc->state == RPROC_CRASHED) 1151 if (rproc->state == RPROC_CRASHED)
1110 complete_all(&rproc->crash_comp); 1152 complete_all(&rproc->crash_comp);
@@ -1196,11 +1238,11 @@ static struct device_type rproc_type = {
1196 * @dev: the underlying device 1238 * @dev: the underlying device
1197 * @name: name of this remote processor 1239 * @name: name of this remote processor
1198 * @ops: platform-specific handlers (mainly start/stop) 1240 * @ops: platform-specific handlers (mainly start/stop)
1199 * @firmware: name of firmware file to load 1241 * @firmware: name of firmware file to load, can be NULL
1200 * @len: length of private data needed by the rproc driver (in bytes) 1242 * @len: length of private data needed by the rproc driver (in bytes)
1201 * 1243 *
1202 * Allocates a new remote processor handle, but does not register 1244 * Allocates a new remote processor handle, but does not register
1203 * it yet. 1245 * it yet. if @firmware is NULL, a default name is used.
1204 * 1246 *
1205 * This function should be used by rproc implementations during initialization 1247 * This function should be used by rproc implementations during initialization
1206 * of the remote processor. 1248 * of the remote processor.
@@ -1219,19 +1261,39 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1219 const char *firmware, int len) 1261 const char *firmware, int len)
1220{ 1262{
1221 struct rproc *rproc; 1263 struct rproc *rproc;
1264 char *p, *template = "rproc-%s-fw";
1265 int name_len = 0;
1222 1266
1223 if (!dev || !name || !ops) 1267 if (!dev || !name || !ops)
1224 return NULL; 1268 return NULL;
1225 1269
1226 rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL); 1270 if (!firmware)
1271 /*
1272 * Make room for default firmware name (minus %s plus '\0').
1273 * If the caller didn't pass in a firmware name then
1274 * construct a default name. We're already glomming 'len'
1275 * bytes onto the end of the struct rproc allocation, so do
1276 * a few more for the default firmware name (but only if
1277 * the caller doesn't pass one).
1278 */
1279 name_len = strlen(name) + strlen(template) - 2 + 1;
1280
1281 rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL);
1227 if (!rproc) { 1282 if (!rproc) {
1228 dev_err(dev, "%s: kzalloc failed\n", __func__); 1283 dev_err(dev, "%s: kzalloc failed\n", __func__);
1229 return NULL; 1284 return NULL;
1230 } 1285 }
1231 1286
1287 if (!firmware) {
1288 p = (char *)rproc + sizeof(struct rproc) + len;
1289 snprintf(p, name_len, template, name);
1290 } else {
1291 p = (char *)firmware;
1292 }
1293
1294 rproc->firmware = p;
1232 rproc->name = name; 1295 rproc->name = name;
1233 rproc->ops = ops; 1296 rproc->ops = ops;
1234 rproc->firmware = firmware;
1235 rproc->priv = &rproc[1]; 1297 rproc->priv = &rproc[1];
1236 1298
1237 device_initialize(&rproc->dev); 1299 device_initialize(&rproc->dev);
@@ -1315,6 +1377,9 @@ int rproc_del(struct rproc *rproc)
1315 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) 1377 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
1316 rproc_remove_virtio_dev(rvdev); 1378 rproc_remove_virtio_dev(rvdev);
1317 1379
1380 /* Free the copy of the resource table */
1381 kfree(rproc->cached_table);
1382
1318 device_del(&rproc->dev); 1383 device_del(&rproc->dev);
1319 1384
1320 return 0; 1385 return 0;
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 0d36f94ab51d..ce283a5b42a1 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -208,41 +208,22 @@ rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
208 return ret; 208 return ret;
209} 209}
210 210
211/** 211static struct elf32_shdr *
212 * rproc_elf_find_rsc_table() - find the resource table 212find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
213 * @rproc: the rproc handle
214 * @fw: the ELF firmware image
215 * @tablesz: place holder for providing back the table size
216 *
217 * This function finds the resource table inside the remote processor's
218 * firmware. It is used both upon the registration of @rproc (in order
219 * to look for and register the supported virito devices), and when the
220 * @rproc is booted.
221 *
222 * Returns the pointer to the resource table if it is found, and write its
223 * size into @tablesz. If a valid table isn't found, NULL is returned
224 * (and @tablesz isn't set).
225 */
226static struct resource_table *
227rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
228 int *tablesz)
229{ 213{
230 struct elf32_hdr *ehdr;
231 struct elf32_shdr *shdr; 214 struct elf32_shdr *shdr;
215 int i;
232 const char *name_table; 216 const char *name_table;
233 struct device *dev = &rproc->dev;
234 struct resource_table *table = NULL; 217 struct resource_table *table = NULL;
235 int i; 218 const u8 *elf_data = (void *)ehdr;
236 const u8 *elf_data = fw->data;
237 219
238 ehdr = (struct elf32_hdr *)elf_data; 220 /* look for the resource table and handle it */
239 shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); 221 shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
240 name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset; 222 name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
241 223
242 /* look for the resource table and handle it */
243 for (i = 0; i < ehdr->e_shnum; i++, shdr++) { 224 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
244 int size = shdr->sh_size; 225 u32 size = shdr->sh_size;
245 int offset = shdr->sh_offset; 226 u32 offset = shdr->sh_offset;
246 227
247 if (strcmp(name_table + shdr->sh_name, ".resource_table")) 228 if (strcmp(name_table + shdr->sh_name, ".resource_table"))
248 continue; 229 continue;
@@ -250,7 +231,7 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
250 table = (struct resource_table *)(elf_data + offset); 231 table = (struct resource_table *)(elf_data + offset);
251 232
252 /* make sure we have the entire table */ 233 /* make sure we have the entire table */
253 if (offset + size > fw->size) { 234 if (offset + size > fw_size || offset + size < size) {
254 dev_err(dev, "resource table truncated\n"); 235 dev_err(dev, "resource table truncated\n");
255 return NULL; 236 return NULL;
256 } 237 }
@@ -280,16 +261,77 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
280 return NULL; 261 return NULL;
281 } 262 }
282 263
283 *tablesz = shdr->sh_size; 264 return shdr;
284 break;
285 } 265 }
286 266
267 return NULL;
268}
269
270/**
271 * rproc_elf_find_rsc_table() - find the resource table
272 * @rproc: the rproc handle
273 * @fw: the ELF firmware image
274 * @tablesz: place holder for providing back the table size
275 *
276 * This function finds the resource table inside the remote processor's
277 * firmware. It is used both upon the registration of @rproc (in order
278 * to look for and register the supported virito devices), and when the
279 * @rproc is booted.
280 *
281 * Returns the pointer to the resource table if it is found, and write its
282 * size into @tablesz. If a valid table isn't found, NULL is returned
283 * (and @tablesz isn't set).
284 */
285static struct resource_table *
286rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
287 int *tablesz)
288{
289 struct elf32_hdr *ehdr;
290 struct elf32_shdr *shdr;
291 struct device *dev = &rproc->dev;
292 struct resource_table *table = NULL;
293 const u8 *elf_data = fw->data;
294
295 ehdr = (struct elf32_hdr *)elf_data;
296
297 shdr = find_table(dev, ehdr, fw->size);
298 if (!shdr)
299 return NULL;
300
301 table = (struct resource_table *)(elf_data + shdr->sh_offset);
302 *tablesz = shdr->sh_size;
303
287 return table; 304 return table;
288} 305}
289 306
307/**
308 * rproc_elf_find_loaded_rsc_table() - find the loaded resource table
309 * @rproc: the rproc handle
310 * @fw: the ELF firmware image
311 *
312 * This function finds the location of the loaded resource table. Don't
313 * call this function if the table wasn't loaded yet - it's a bug if you do.
314 *
315 * Returns the pointer to the resource table if it is found or NULL otherwise.
316 * If the table wasn't loaded yet the result is unspecified.
317 */
318static struct resource_table *
319rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
320{
321 struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
322 struct elf32_shdr *shdr;
323
324 shdr = find_table(&rproc->dev, ehdr, fw->size);
325 if (!shdr)
326 return NULL;
327
328 return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
329}
330
290const struct rproc_fw_ops rproc_elf_fw_ops = { 331const struct rproc_fw_ops rproc_elf_fw_ops = {
291 .load = rproc_elf_load_segments, 332 .load = rproc_elf_load_segments,
292 .find_rsc_table = rproc_elf_find_rsc_table, 333 .find_rsc_table = rproc_elf_find_rsc_table,
334 .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
293 .sanity_check = rproc_elf_sanity_check, 335 .sanity_check = rproc_elf_sanity_check,
294 .get_boot_addr = rproc_elf_get_boot_addr 336 .get_boot_addr = rproc_elf_get_boot_addr
295}; 337};
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 7bb66482d061..157e762c1571 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -27,7 +27,8 @@ struct rproc;
27 27
28/** 28/**
29 * struct rproc_fw_ops - firmware format specific operations. 29 * struct rproc_fw_ops - firmware format specific operations.
30 * @find_rsc_table: finds the resource table inside the firmware image 30 * @find_rsc_table: find the resource table inside the firmware image
31 * @find_loaded_rsc_table: find the loaded resouce table
31 * @load: load firmeware to memory, where the remote processor 32 * @load: load firmeware to memory, where the remote processor
32 * expects to find it 33 * expects to find it
33 * @sanity_check: sanity check the fw image 34 * @sanity_check: sanity check the fw image
@@ -37,6 +38,8 @@ struct rproc_fw_ops {
37 struct resource_table *(*find_rsc_table) (struct rproc *rproc, 38 struct resource_table *(*find_rsc_table) (struct rproc *rproc,
38 const struct firmware *fw, 39 const struct firmware *fw,
39 int *tablesz); 40 int *tablesz);
41 struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc,
42 const struct firmware *fw);
40 int (*load)(struct rproc *rproc, const struct firmware *fw); 43 int (*load)(struct rproc *rproc, const struct firmware *fw);
41 int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); 44 int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
42 u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); 45 u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
@@ -102,6 +105,16 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
102 return NULL; 105 return NULL;
103} 106}
104 107
108static inline
109struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
110 const struct firmware *fw)
111{
112 if (rproc->fw_ops->find_loaded_rsc_table)
113 return rproc->fw_ops->find_loaded_rsc_table(rproc, fw);
114
115 return NULL;
116}
117
105extern const struct rproc_fw_ops rproc_elf_fw_ops; 118extern const struct rproc_fw_ops rproc_elf_fw_ops;
106 119
107#endif /* REMOTEPROC_INTERNAL_H */ 120#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index afed9b7731c4..b09c75c21b60 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -173,25 +173,35 @@ error:
173 return ret; 173 return ret;
174} 174}
175 175
176/*
177 * We don't support yet real virtio status semantics.
178 *
179 * The plan is to provide this via the VDEV resource entry
180 * which is part of the firmware: this way the remote processor
181 * will be able to access the status values as set by us.
182 */
183static u8 rproc_virtio_get_status(struct virtio_device *vdev) 176static u8 rproc_virtio_get_status(struct virtio_device *vdev)
184{ 177{
185 return 0; 178 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
179 struct fw_rsc_vdev *rsc;
180
181 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
182
183 return rsc->status;
186} 184}
187 185
188static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status) 186static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
189{ 187{
188 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
189 struct fw_rsc_vdev *rsc;
190
191 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
192
193 rsc->status = status;
190 dev_dbg(&vdev->dev, "status: %d\n", status); 194 dev_dbg(&vdev->dev, "status: %d\n", status);
191} 195}
192 196
193static void rproc_virtio_reset(struct virtio_device *vdev) 197static void rproc_virtio_reset(struct virtio_device *vdev)
194{ 198{
199 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
200 struct fw_rsc_vdev *rsc;
201
202 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
203
204 rsc->status = 0;
195 dev_dbg(&vdev->dev, "reset !\n"); 205 dev_dbg(&vdev->dev, "reset !\n");
196} 206}
197 207
@@ -199,13 +209,19 @@ static void rproc_virtio_reset(struct virtio_device *vdev)
199static u32 rproc_virtio_get_features(struct virtio_device *vdev) 209static u32 rproc_virtio_get_features(struct virtio_device *vdev)
200{ 210{
201 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); 211 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
212 struct fw_rsc_vdev *rsc;
213
214 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
202 215
203 return rvdev->dfeatures; 216 return rsc->dfeatures;
204} 217}
205 218
206static void rproc_virtio_finalize_features(struct virtio_device *vdev) 219static void rproc_virtio_finalize_features(struct virtio_device *vdev)
207{ 220{
208 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); 221 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
222 struct fw_rsc_vdev *rsc;
223
224 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
209 225
210 /* Give virtio_ring a chance to accept features */ 226 /* Give virtio_ring a chance to accept features */
211 vring_transport_features(vdev); 227 vring_transport_features(vdev);
@@ -213,13 +229,44 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev)
213 /* 229 /*
214 * Remember the finalized features of our vdev, and provide it 230 * Remember the finalized features of our vdev, and provide it
215 * to the remote processor once it is powered on. 231 * to the remote processor once it is powered on.
216 *
217 * Similarly to the status field, we don't expose yet the negotiated
218 * features to the remote processors at this point. This will be
219 * fixed as part of a small resource table overhaul and then an
220 * extension of the virtio resource entries.
221 */ 232 */
222 rvdev->gfeatures = vdev->features[0]; 233 rsc->gfeatures = vdev->features[0];
234}
235
236static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
237 void *buf, unsigned len)
238{
239 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
240 struct fw_rsc_vdev *rsc;
241 void *cfg;
242
243 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
244 cfg = &rsc->vring[rsc->num_of_vrings];
245
246 if (offset + len > rsc->config_len || offset + len < len) {
247 dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n");
248 return;
249 }
250
251 memcpy(buf, cfg + offset, len);
252}
253
254static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
255 const void *buf, unsigned len)
256{
257 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
258 struct fw_rsc_vdev *rsc;
259 void *cfg;
260
261 rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
262 cfg = &rsc->vring[rsc->num_of_vrings];
263
264 if (offset + len > rsc->config_len || offset + len < len) {
265 dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n");
266 return;
267 }
268
269 memcpy(cfg + offset, buf, len);
223} 270}
224 271
225static const struct virtio_config_ops rproc_virtio_config_ops = { 272static const struct virtio_config_ops rproc_virtio_config_ops = {
@@ -230,6 +277,8 @@ static const struct virtio_config_ops rproc_virtio_config_ops = {
230 .reset = rproc_virtio_reset, 277 .reset = rproc_virtio_reset,
231 .set_status = rproc_virtio_set_status, 278 .set_status = rproc_virtio_set_status,
232 .get_status = rproc_virtio_get_status, 279 .get_status = rproc_virtio_get_status,
280 .get = rproc_virtio_get,
281 .set = rproc_virtio_set,
233}; 282};
234 283
235/* 284/*
diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c
index fb95c4220052..1ec39a4c0b3e 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -64,26 +64,18 @@ static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
64} 64}
65 65
66/* Find the entry for resource table in the Table of Content */ 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) 67static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
68{ 68{
69 int i; 69 int i;
70 struct ste_toc *toc; 70 const struct ste_toc *toc;
71 71 toc = data;
72 if (!fw)
73 return NULL;
74
75 toc = (void *)fw->data;
76 72
77 /* Search the table for the resource table */ 73 /* Search the table for the resource table */
78 for (i = 0; i < SPROC_MAX_TOC_ENTRIES && 74 for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
79 toc->table[i].start != 0xffffffff; i++) { 75 toc->table[i].start != 0xffffffff; i++) {
80
81 if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME, 76 if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
82 sizeof(toc->table[i].name))) { 77 sizeof(toc->table[i].name)))
83 if (toc->table[i].start > fw->size)
84 return NULL;
85 return &toc->table[i]; 78 return &toc->table[i];
86 }
87 } 79 }
88 80
89 return NULL; 81 return NULL;
@@ -96,9 +88,12 @@ sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
96{ 88{
97 struct sproc *sproc = rproc->priv; 89 struct sproc *sproc = rproc->priv;
98 struct resource_table *table; 90 struct resource_table *table;
99 struct ste_toc_entry *entry; 91 const struct ste_toc_entry *entry;
100 92
101 entry = sproc_find_rsc_entry(fw); 93 if (!fw)
94 return NULL;
95
96 entry = sproc_find_rsc_entry(fw->data);
102 if (!entry) { 97 if (!entry) {
103 sproc_err(sproc, "resource table not found in fw\n"); 98 sproc_err(sproc, "resource table not found in fw\n");
104 return NULL; 99 return NULL;
@@ -149,10 +144,30 @@ sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
149 return table; 144 return table;
150} 145}
151 146
147/* Find the resource table inside the remote processor's firmware. */
148static struct resource_table *
149sproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
150{
151 struct sproc *sproc = rproc->priv;
152 const struct ste_toc_entry *entry;
153
154 if (!fw || !sproc->fw_addr)
155 return NULL;
156
157 entry = sproc_find_rsc_entry(sproc->fw_addr);
158 if (!entry) {
159 sproc_err(sproc, "resource table not found in fw\n");
160 return NULL;
161 }
162
163 return sproc->fw_addr + entry->start;
164}
165
152/* STE modem firmware handler operations */ 166/* STE modem firmware handler operations */
153const struct rproc_fw_ops sproc_fw_ops = { 167const struct rproc_fw_ops sproc_fw_ops = {
154 .load = sproc_load_segments, 168 .load = sproc_load_segments,
155 .find_rsc_table = sproc_find_rsc_table, 169 .find_rsc_table = sproc_find_rsc_table,
170 .find_loaded_rsc_table = sproc_find_loaded_rsc_table,
156}; 171};
157 172
158/* Kick the modem with specified notification id */ 173/* Kick the modem with specified notification id */
@@ -198,7 +213,7 @@ static int sproc_start(struct rproc *rproc)
198 } 213 }
199 214
200 /* Subscribe to notifications */ 215 /* Subscribe to notifications */
201 for (i = 0; i < rproc->max_notifyid; i++) { 216 for (i = 0; i <= rproc->max_notifyid; i++) {
202 err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i); 217 err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i);
203 if (err) { 218 if (err) {
204 sproc_err(sproc, 219 sproc_err(sproc,
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index faf33324c78f..9e7e745dac55 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -401,6 +401,9 @@ enum rproc_crash_type {
401 * @crash_comp: completion used to sync crash handler and the rproc reload 401 * @crash_comp: completion used to sync crash handler and the rproc reload
402 * @recovery_disabled: flag that state if recovery was disabled 402 * @recovery_disabled: flag that state if recovery was disabled
403 * @max_notifyid: largest allocated notify id. 403 * @max_notifyid: largest allocated notify id.
404 * @table_ptr: pointer to the resource table in effect
405 * @cached_table: copy of the resource table
406 * @table_csum: checksum of the resource table
404 */ 407 */
405struct rproc { 408struct rproc {
406 struct klist_node node; 409 struct klist_node node;
@@ -429,9 +432,13 @@ struct rproc {
429 struct completion crash_comp; 432 struct completion crash_comp;
430 bool recovery_disabled; 433 bool recovery_disabled;
431 int max_notifyid; 434 int max_notifyid;
435 struct resource_table *table_ptr;
436 struct resource_table *cached_table;
437 u32 table_csum;
432}; 438};
433 439
434/* we currently support only two vrings per rvdev */ 440/* we currently support only two vrings per rvdev */
441
435#define RVDEV_NUM_VRINGS 2 442#define RVDEV_NUM_VRINGS 2
436 443
437/** 444/**
@@ -462,16 +469,14 @@ struct rproc_vring {
462 * @rproc: the rproc handle 469 * @rproc: the rproc handle
463 * @vdev: the virio device 470 * @vdev: the virio device
464 * @vring: the vrings for this vdev 471 * @vring: the vrings for this vdev
465 * @dfeatures: virtio device features 472 * @rsc_offset: offset of the vdev's resource entry
466 * @gfeatures: virtio guest features
467 */ 473 */
468struct rproc_vdev { 474struct rproc_vdev {
469 struct list_head node; 475 struct list_head node;
470 struct rproc *rproc; 476 struct rproc *rproc;
471 struct virtio_device vdev; 477 struct virtio_device vdev;
472 struct rproc_vring vring[RVDEV_NUM_VRINGS]; 478 struct rproc_vring vring[RVDEV_NUM_VRINGS];
473 unsigned long dfeatures; 479 u32 rsc_offset;
474 unsigned long gfeatures;
475}; 480};
476 481
477struct rproc *rproc_alloc(struct device *dev, const char *name, 482struct rproc *rproc_alloc(struct device *dev, const char *name,