Commit de9c9f86be0dc3495de98dc65c80abe6e7c7d643

Authored by Linus Torvalds

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()

Showing 9 changed files Side-by-side Diff

drivers/remoteproc/Kconfig
... ... @@ -4,13 +4,15 @@
4 4 config REMOTEPROC
5 5 tristate
6 6 depends on HAS_DMA
  7 + select CRC32
7 8 select FW_LOADER
8 9 select VIRTIO
  10 + select VIRTUALIZATION
9 11  
10 12 config OMAP_REMOTEPROC
11 13 tristate "OMAP remoteproc support"
12 14 depends on HAS_DMA
13   - depends on ARCH_OMAP4
  15 + depends on ARCH_OMAP4 || SOC_OMAP5
14 16 depends on OMAP_IOMMU
15 17 depends on OMAP_MBOX_FWK
16 18 select REMOTEPROC
... ... @@ -37,6 +39,29 @@
37 39 Say y or m here to support STE-Modem shared memory driver.
38 40 This can be either built-in or a loadable module.
39 41 If unsure say N.
  42 +
  43 +config 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.
40 65  
41 66 endmenu
drivers/remoteproc/Makefile
... ... @@ -9,4 +9,5 @@
9 9 remoteproc-y += remoteproc_elf_loader.o
10 10 obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
11 11 obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
  12 +obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
drivers/remoteproc/da8xx_remoteproc.c
  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 +
  26 +static char *da8xx_fw_name;
  27 +module_param(da8xx_fw_name, charp, S_IRUGO);
  28 +MODULE_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 + */
  52 +struct 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 + */
  68 +static 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 + */
  88 +static 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 +
  116 +static 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 +
  137 +static 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 */
  147 +static 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 +
  155 +static struct rproc_ops da8xx_rproc_ops = {
  156 + .start = da8xx_rproc_start,
  157 + .stop = da8xx_rproc_stop,
  158 + .kick = da8xx_rproc_kick,
  159 +};
  160 +
  161 +static 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 +
  177 +static 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 +
  275 +free_rproc:
  276 + rproc_put(rproc);
  277 +
  278 + return ret;
  279 +}
  280 +
  281 +static 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 +
  312 +static 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 +
  321 +module_platform_driver(da8xx_rproc_driver);
  322 +
  323 +MODULE_LICENSE("GPL v2");
  324 +MODULE_DESCRIPTION("DA8XX Remote Processor control driver");
drivers/remoteproc/remoteproc_core.c
... ... @@ -37,6 +37,7 @@
37 37 #include <linux/iommu.h>
38 38 #include <linux/idr.h>
39 39 #include <linux/elf.h>
  40 +#include <linux/crc32.h>
40 41 #include <linux/virtio_ids.h>
41 42 #include <linux/virtio_ring.h>
42 43 #include <asm/byteorder.h>
... ... @@ -45,7 +46,8 @@
45 46  
46 47 typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
47 48 struct resource_table *table, int len);
48   -typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
  49 +typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
  50 + void *, int offset, int avail);
49 51  
50 52 /* Unique indices for remoteproc devices */
51 53 static DEFINE_IDA(rproc_dev_index);
... ... @@ -192,6 +194,7 @@
192 194 struct rproc *rproc = rvdev->rproc;
193 195 struct device *dev = &rproc->dev;
194 196 struct rproc_vring *rvring = &rvdev->vring[i];
  197 + struct fw_rsc_vdev *rsc;
195 198 dma_addr_t dma;
196 199 void *va;
197 200 int ret, size, notifyid;
... ... @@ -202,7 +205,6 @@
202 205 /*
203 206 * Allocate non-cacheable memory for the vring. In the future
204 207 * this call will also configure the IOMMU for us
205   - * TODO: let the rproc know the da of this vring
206 208 */
207 209 va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
208 210 if (!va) {
... ... @@ -213,7 +215,6 @@
213 215 /*
214 216 * Assign an rproc-wide unique index for this vring
215 217 * TODO: assign a notifyid for rvdev updates as well
216   - * TODO: let the rproc know the notifyid of this vring
217 218 * TODO: support predefined notifyids (via resource table)
218 219 */
219 220 ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
... ... @@ -224,9 +225,6 @@
224 225 }
225 226 notifyid = ret;
226 227  
227   - /* Store largest notifyid */
228   - rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
229   -
230 228 dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
231 229 (unsigned long long)dma, size, notifyid);
232 230  
... ... @@ -234,6 +232,15 @@
234 232 rvring->dma = dma;
235 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 244 return 0;
238 245 }
239 246  
240 247  
241 248  
... ... @@ -268,25 +275,20 @@
268 275 return 0;
269 276 }
270 277  
271   -static 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   -
278 278 void rproc_free_vring(struct rproc_vring *rvring)
279 279 {
280 280 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
281 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 285 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
285 286 idr_remove(&rproc->notifyids, rvring->notifyid);
286 287  
287   - /* Find the largest remaining notifyid */
288   - idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
289   - rproc->max_notifyid = maxid;
  288 + /* reset resource entry info */
  289 + rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset;
  290 + rsc->vring[idx].da = 0;
  291 + rsc->vring[idx].notifyid = -1;
290 292 }
291 293  
292 294 /**
... ... @@ -317,7 +319,7 @@
317 319 * Returns 0 on success, or an appropriate error code otherwise
318 320 */
319 321 static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
320   - int avail)
  322 + int offset, int avail)
321 323 {
322 324 struct device *dev = &rproc->dev;
323 325 struct rproc_vdev *rvdev;
... ... @@ -358,8 +360,8 @@
358 360 goto free_rvdev;
359 361 }
360 362  
361   - /* remember the device features */
362   - rvdev->dfeatures = rsc->dfeatures;
  363 + /* remember the resource offset*/
  364 + rvdev->rsc_offset = offset;
363 365  
364 366 list_add_tail(&rvdev->node, &rproc->rvdevs);
365 367  
... ... @@ -394,7 +396,7 @@
394 396 * Returns 0 on success, or an appropriate error code otherwise
395 397 */
396 398 static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
397   - int avail)
  399 + int offset, int avail)
398 400 {
399 401 struct rproc_mem_entry *trace;
400 402 struct device *dev = &rproc->dev;
... ... @@ -476,7 +478,7 @@
476 478 * are outside those ranges.
477 479 */
478 480 static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
479   - int avail)
  481 + int offset, int avail)
480 482 {
481 483 struct rproc_mem_entry *mapping;
482 484 struct device *dev = &rproc->dev;
... ... @@ -549,7 +551,9 @@
549 551 * pressure is important; it may have a substantial impact on performance.
550 552 */
551 553 static 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 558 struct rproc_mem_entry *carveout, *mapping;
555 559 struct device *dev = &rproc->dev;
556 560  
557 561  
558 562  
559 563  
... ... @@ -671,28 +675,45 @@
671 675 return ret;
672 676 }
673 677  
  678 +static 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 688 * A lookup table for resource handlers. The indices are defined in
676 689 * enum fw_resource_type.
677 690 */
678   -static rproc_handle_resource_t rproc_handle_rsc[] = {
  691 +static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
679 692 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
680 693 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
681 694 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
682 695 [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
683 696 };
684 697  
  698 +static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = {
  699 + [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
  700 +};
  701 +
  702 +static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = {
  703 + [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings,
  704 +};
  705 +
685 706 /* handle firmware resource entries before booting the remote processor */
686   -static int
687   -rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len)
  707 +static int rproc_handle_resources(struct rproc *rproc, int len,
  708 + rproc_handle_resource_t handlers[RSC_LAST])
688 709 {
689 710 struct device *dev = &rproc->dev;
690 711 rproc_handle_resource_t handler;
691 712 int ret = 0, i;
692 713  
693   - for (i = 0; i < table->num; i++) {
694   - int offset = table->offset[i];
695   - struct fw_rsc_hdr *hdr = (void *)table + offset;
  714 + for (i = 0; i < rproc->table_ptr->num; i++) {
  715 + int offset = rproc->table_ptr->offset[i];
  716 + struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
696 717 int avail = len - offset - sizeof(*hdr);
697 718 void *rsc = (void *)hdr + sizeof(*hdr);
698 719  
699 720  
... ... @@ -709,11 +730,11 @@
709 730 continue;
710 731 }
711 732  
712   - handler = rproc_handle_rsc[hdr->type];
  733 + handler = handlers[hdr->type];
713 734 if (!handler)
714 735 continue;
715 736  
716   - ret = handler(rproc, rsc, avail);
  737 + ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
717 738 if (ret)
718 739 break;
719 740 }
... ... @@ -721,40 +742,6 @@
721 742 return ret;
722 743 }
723 744  
724   -/* handle firmware resource entries while registering the remote processor */
725   -static int
726   -rproc_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)
752   - break;
753   - }
754   -
755   - return ret;
756   -}
757   -
758 745 /**
759 746 * rproc_resource_cleanup() - clean up and free all acquired resources
760 747 * @rproc: rproc handle
761 748  
... ... @@ -805,9 +792,12 @@
805 792 {
806 793 struct device *dev = &rproc->dev;
807 794 const char *name = rproc->firmware;
808   - struct resource_table *table;
  795 + struct resource_table *table, *loaded_table;
809 796 int ret, tablesz;
810 797  
  798 + if (!rproc->table_ptr)
  799 + return -ENOMEM;
  800 +
811 801 ret = rproc_fw_sanity_check(rproc, fw);
812 802 if (ret)
813 803 return ret;
814 804  
... ... @@ -833,8 +823,15 @@
833 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 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 835 if (ret) {
839 836 dev_err(dev, "Failed to process resources: %d\n", ret);
840 837 goto clean_up;
... ... @@ -847,6 +844,19 @@
847 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 860 /* power up the remote processor */
851 861 ret = rproc->ops->start(rproc);
852 862 if (ret) {
... ... @@ -854,6 +864,13 @@
854 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 874 rproc->state = RPROC_RUNNING;
858 875  
859 876 dev_info(dev, "remote processor %s is now up\n", rproc->name);
860 877  
... ... @@ -888,11 +905,30 @@
888 905 if (!table)
889 906 goto out;
890 907  
891   - /* look for virtio devices and register them */
892   - ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
  908 + rproc->table_csum = crc32(0, 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 926 if (ret)
894 927 goto out;
895 928  
  929 + /* look for virtio devices and register them */
  930 + ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
  931 +
896 932 out:
897 933 release_firmware(fw);
898 934 /* allow rproc_del() contexts, if any, to proceed */
... ... @@ -950,6 +986,9 @@
950 986 /* wait until there is no more rproc users */
951 987 wait_for_completion(&rproc->crash_comp);
952 988  
  989 + /* Free the copy of the resource table */
  990 + kfree(rproc->cached_table);
  991 +
953 992 return rproc_add_virtio_devices(rproc);
954 993 }
955 994  
... ... @@ -1105,6 +1144,9 @@
1105 1144  
1106 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 1150 /* if in crash state, unlock crash handler */
1109 1151 if (rproc->state == RPROC_CRASHED)
1110 1152 complete_all(&rproc->crash_comp);
1111 1153  
... ... @@ -1196,11 +1238,11 @@
1196 1238 * @dev: the underlying device
1197 1239 * @name: name of this remote processor
1198 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 1242 * @len: length of private data needed by the rproc driver (in bytes)
1201 1243 *
1202 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 1247 * This function should be used by rproc implementations during initialization
1206 1248 * of the remote processor.
1207 1249  
1208 1250  
1209 1251  
... ... @@ -1219,19 +1261,39 @@
1219 1261 const char *firmware, int len)
1220 1262 {
1221 1263 struct rproc *rproc;
  1264 + char *p, *template = "rproc-%s-fw";
  1265 + int name_len = 0;
1222 1266  
1223 1267 if (!dev || !name || !ops)
1224 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 1282 if (!rproc) {
1228 1283 dev_err(dev, "%s: kzalloc failed\n", __func__);
1229 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 1295 rproc->name = name;
1233 1296 rproc->ops = ops;
1234   - rproc->firmware = firmware;
1235 1297 rproc->priv = &rproc[1];
1236 1298  
1237 1299 device_initialize(&rproc->dev);
... ... @@ -1314,6 +1376,9 @@
1314 1376 /* clean up remote vdev entries */
1315 1377 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
1316 1378 rproc_remove_virtio_dev(rvdev);
  1379 +
  1380 + /* Free the copy of the resource table */
  1381 + kfree(rproc->cached_table);
1317 1382  
1318 1383 device_del(&rproc->dev);
1319 1384  
drivers/remoteproc/remoteproc_elf_loader.c
... ... @@ -208,41 +208,22 @@
208 208 return ret;
209 209 }
210 210  
211   -/**
212   - * rproc_elf_find_rsc_table() - find the resource table
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   - */
226   -static struct resource_table *
227   -rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
228   - int *tablesz)
  211 +static struct elf32_shdr *
  212 +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
229 213 {
230   - struct elf32_hdr *ehdr;
231 214 struct elf32_shdr *shdr;
  215 + int i;
232 216 const char *name_table;
233   - struct device *dev = &rproc->dev;
234 217 struct resource_table *table = NULL;
235   - int i;
236   - const u8 *elf_data = fw->data;
  218 + const u8 *elf_data = (void *)ehdr;
237 219  
238   - ehdr = (struct elf32_hdr *)elf_data;
  220 + /* look for the resource table and handle it */
239 221 shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
240 222 name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
241 223  
242   - /* look for the resource table and handle it */
243 224 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
244   - int size = shdr->sh_size;
245   - int offset = shdr->sh_offset;
  225 + u32 size = shdr->sh_size;
  226 + u32 offset = shdr->sh_offset;
246 227  
247 228 if (strcmp(name_table + shdr->sh_name, ".resource_table"))
248 229 continue;
... ... @@ -250,7 +231,7 @@
250 231 table = (struct resource_table *)(elf_data + offset);
251 232  
252 233 /* make sure we have the entire table */
253   - if (offset + size > fw->size) {
  234 + if (offset + size > fw_size || offset + size < size) {
254 235 dev_err(dev, "resource table truncated\n");
255 236 return NULL;
256 237 }
257 238  
258 239  
259 240  
... ... @@ -280,16 +261,77 @@
280 261 return NULL;
281 262 }
282 263  
283   - *tablesz = shdr->sh_size;
284   - break;
  264 + return shdr;
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 + */
  285 +static struct resource_table *
  286 +rproc_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 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 + */
  318 +static struct resource_table *
  319 +rproc_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 +
290 331 const struct rproc_fw_ops rproc_elf_fw_ops = {
291 332 .load = rproc_elf_load_segments,
292 333 .find_rsc_table = rproc_elf_find_rsc_table,
  334 + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
293 335 .sanity_check = rproc_elf_sanity_check,
294 336 .get_boot_addr = rproc_elf_get_boot_addr
295 337 };
drivers/remoteproc/remoteproc_internal.h
... ... @@ -27,7 +27,8 @@
27 27  
28 28 /**
29 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 32 * @load: load firmeware to memory, where the remote processor
32 33 * expects to find it
33 34 * @sanity_check: sanity check the fw image
... ... @@ -37,6 +38,8 @@
37 38 struct resource_table *(*find_rsc_table) (struct rproc *rproc,
38 39 const struct firmware *fw,
39 40 int *tablesz);
  41 + struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc,
  42 + const struct firmware *fw);
40 43 int (*load)(struct rproc *rproc, const struct firmware *fw);
41 44 int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
42 45 u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
... ... @@ -100,6 +103,16 @@
100 103 return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz);
101 104  
102 105 return NULL;
  106 +}
  107 +
  108 +static inline
  109 +struct 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;
103 116 }
104 117  
105 118 extern const struct rproc_fw_ops rproc_elf_fw_ops;
drivers/remoteproc/remoteproc_virtio.c
... ... @@ -173,25 +173,35 @@
173 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   - */
183 176 static 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  
188 186 static 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 194 dev_dbg(&vdev->dev, "status: %d\n", status);
191 195 }
192 196  
193 197 static 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 205 dev_dbg(&vdev->dev, "reset !\n");
196 206 }
197 207  
198 208  
199 209  
200 210  
201 211  
202 212  
203 213  
... ... @@ -199,29 +209,66 @@
199 209 static u32 rproc_virtio_get_features(struct virtio_device *vdev)
200 210 {
201 211 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
  212 + struct fw_rsc_vdev *rsc;
202 213  
203   - return rvdev->dfeatures;
  214 + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
  215 +
  216 + return rsc->dfeatures;
204 217 }
205 218  
206 219 static void rproc_virtio_finalize_features(struct virtio_device *vdev)
207 220 {
208 221 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
  222 + struct fw_rsc_vdev *rsc;
209 223  
  224 + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
  225 +
210 226 /* Give virtio_ring a chance to accept features */
211 227 vring_transport_features(vdev);
212 228  
213 229 /*
214 230 * Remember the finalized features of our vdev, and provide it
215 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];
223 234 }
224 235  
  236 +static 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 +
  254 +static 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);
  270 +}
  271 +
225 272 static const struct virtio_config_ops rproc_virtio_config_ops = {
226 273 .get_features = rproc_virtio_get_features,
227 274 .finalize_features = rproc_virtio_finalize_features,
... ... @@ -230,6 +277,8 @@
230 277 .reset = rproc_virtio_reset,
231 278 .set_status = rproc_virtio_set_status,
232 279 .get_status = rproc_virtio_get_status,
  280 + .get = rproc_virtio_get,
  281 + .set = rproc_virtio_set,
233 282 };
234 283  
235 284 /*
drivers/remoteproc/ste_modem_rproc.c
... ... @@ -64,26 +64,18 @@
64 64 }
65 65  
66 66 /* Find the entry for resource table in the Table of Content */
67   -static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
  67 +static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
68 68 {
69 69 int i;
70   - struct ste_toc *toc;
  70 + const struct ste_toc *toc;
  71 + toc = data;
71 72  
72   - if (!fw)
73   - return NULL;
74   -
75   - toc = (void *)fw->data;
76   -
77 73 /* Search the table for the resource table */
78 74 for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
79 75 toc->table[i].start != 0xffffffff; i++) {
80   -
81 76 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;
  77 + sizeof(toc->table[i].name)))
85 78 return &toc->table[i];
86   - }
87 79 }
88 80  
89 81 return NULL;
90 82  
... ... @@ -96,9 +88,12 @@
96 88 {
97 89 struct sproc *sproc = rproc->priv;
98 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 97 if (!entry) {
103 98 sproc_err(sproc, "resource table not found in fw\n");
104 99 return NULL;
105 100  
... ... @@ -149,10 +144,30 @@
149 144 return table;
150 145 }
151 146  
  147 +/* Find the resource table inside the remote processor's firmware. */
  148 +static struct resource_table *
  149 +sproc_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 166 /* STE modem firmware handler operations */
153 167 const struct rproc_fw_ops sproc_fw_ops = {
154 168 .load = sproc_load_segments,
155 169 .find_rsc_table = sproc_find_rsc_table,
  170 + .find_loaded_rsc_table = sproc_find_loaded_rsc_table,
156 171 };
157 172  
158 173 /* Kick the modem with specified notification id */
... ... @@ -198,7 +213,7 @@
198 213 }
199 214  
200 215 /* Subscribe to notifications */
201   - for (i = 0; i < rproc->max_notifyid; i++) {
  216 + for (i = 0; i <= rproc->max_notifyid; i++) {
202 217 err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i);
203 218 if (err) {
204 219 sproc_err(sproc,
include/linux/remoteproc.h
... ... @@ -401,6 +401,9 @@
401 401 * @crash_comp: completion used to sync crash handler and the rproc reload
402 402 * @recovery_disabled: flag that state if recovery was disabled
403 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 */
405 408 struct rproc {
406 409 struct klist_node node;
407 410  
... ... @@ -429,9 +432,13 @@
429 432 struct completion crash_comp;
430 433 bool recovery_disabled;
431 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 440 /* we currently support only two vrings per rvdev */
  441 +
435 442 #define RVDEV_NUM_VRINGS 2
436 443  
437 444 /**
438 445  
... ... @@ -462,16 +469,14 @@
462 469 * @rproc: the rproc handle
463 470 * @vdev: the virio device
464 471 * @vring: the vrings for this vdev
465   - * @dfeatures: virtio device features
466   - * @gfeatures: virtio guest features
  472 + * @rsc_offset: offset of the vdev's resource entry
467 473 */
468 474 struct rproc_vdev {
469 475 struct list_head node;
470 476 struct rproc *rproc;
471 477 struct virtio_device vdev;
472 478 struct rproc_vring vring[RVDEV_NUM_VRINGS];
473   - unsigned long dfeatures;
474   - unsigned long gfeatures;
  479 + u32 rsc_offset;
475 480 };
476 481  
477 482 struct rproc *rproc_alloc(struct device *dev, const char *name,