Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+678 -139
+26 -1
drivers/remoteproc/Kconfig
··· 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 ··· 39 37 Say y or m here to support STE-Modem shared memory driver. 40 38 This can be either built-in or a loadable module. 41 39 If unsure say N. 40 + 41 + config DA8XX_REMOTEPROC 42 + tristate "DA8xx/OMAP-L13x remoteproc support" 43 + depends on ARCH_DAVINCI_DA8XX 44 + select CMA 45 + select REMOTEPROC 46 + select RPMSG 47 + help 48 + Say y here to support DA8xx/OMAP-L13x remote processors via the 49 + remote processor framework. 50 + 51 + You want to say y here in order to enable AMP 52 + use-cases to run on your platform (multimedia codecs are 53 + offloaded to remote DSP processors using this framework). 54 + 55 + This module controls the name of the firmware file that gets 56 + loaded on the DSP. This file must reside in the /lib/firmware 57 + directory. It can be specified via the module parameter 58 + da8xx_fw_name=<filename>, and if not specified will default to 59 + "rproc-dsp-fw". 60 + 61 + It's safe to say n here if you're not interested in multimedia 62 + offloading. 42 63 43 64 endmenu
+1
drivers/remoteproc/Makefile
··· 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
+324
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");
+138 -73
drivers/remoteproc/remoteproc_core.c
··· 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> ··· 46 45 47 46 typedef int (*rproc_handle_resources_t)(struct rproc *rproc, 48 47 struct resource_table *table, int len); 49 - typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); 48 + typedef int (*rproc_handle_resource_t)(struct rproc *rproc, 49 + void *, int offset, int avail); 50 50 51 51 /* Unique indices for remoteproc devices */ 52 52 static DEFINE_IDA(rproc_dev_index); ··· 194 192 struct rproc *rproc = rvdev->rproc; 195 193 struct device *dev = &rproc->dev; 196 194 struct rproc_vring *rvring = &rvdev->vring[i]; 195 + struct fw_rsc_vdev *rsc; 197 196 dma_addr_t dma; 198 197 void *va; 199 198 int ret, size, notifyid; ··· 205 202 /* 206 203 * Allocate non-cacheable memory for the vring. In the future 207 204 * this call will also configure the IOMMU for us 208 - * TODO: let the rproc know the da of this vring 209 205 */ 210 206 va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL); 211 207 if (!va) { ··· 215 213 /* 216 214 * Assign an rproc-wide unique index for this vring 217 215 * TODO: assign a notifyid for rvdev updates as well 218 - * TODO: let the rproc know the notifyid of this vring 219 216 * TODO: support predefined notifyids (via resource table) 220 217 */ 221 218 ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); ··· 225 224 } 226 225 notifyid = ret; 227 226 228 - /* Store largest notifyid */ 229 - rproc->max_notifyid = max(rproc->max_notifyid, notifyid); 230 - 231 227 dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va, 232 228 (unsigned long long)dma, size, notifyid); 233 229 ··· 232 234 rvring->dma = dma; 233 235 rvring->notifyid = notifyid; 234 236 237 + /* 238 + * Let the rproc know the notifyid and da of this vring. 239 + * Not all platforms use dma_alloc_coherent to automatically 240 + * set up the iommu. In this case the device address (da) will 241 + * hold the physical address and not the device address. 242 + */ 243 + rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; 244 + rsc->vring[i].da = dma; 245 + rsc->vring[i].notifyid = notifyid; 235 246 return 0; 236 247 } 237 248 ··· 275 268 return 0; 276 269 } 277 270 278 - static int rproc_max_notifyid(int id, void *p, void *data) 279 - { 280 - int *maxid = data; 281 - *maxid = max(*maxid, id); 282 - return 0; 283 - } 284 - 285 271 void rproc_free_vring(struct rproc_vring *rvring) 286 272 { 287 273 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); 288 274 struct rproc *rproc = rvring->rvdev->rproc; 289 - int maxid = 0; 275 + int idx = rvring->rvdev->vring - rvring; 276 + struct fw_rsc_vdev *rsc; 290 277 291 278 dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); 292 279 idr_remove(&rproc->notifyids, rvring->notifyid); 293 280 294 - /* Find the largest remaining notifyid */ 295 - idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid); 296 - rproc->max_notifyid = maxid; 281 + /* reset resource entry info */ 282 + rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset; 283 + rsc->vring[idx].da = 0; 284 + rsc->vring[idx].notifyid = -1; 297 285 } 298 286 299 287 /** ··· 319 317 * Returns 0 on success, or an appropriate error code otherwise 320 318 */ 321 319 static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, 322 - int avail) 320 + int offset, int avail) 323 321 { 324 322 struct device *dev = &rproc->dev; 325 323 struct rproc_vdev *rvdev; ··· 360 358 goto free_rvdev; 361 359 } 362 360 363 - /* remember the device features */ 364 - rvdev->dfeatures = rsc->dfeatures; 361 + /* remember the resource offset*/ 362 + rvdev->rsc_offset = offset; 365 363 366 364 list_add_tail(&rvdev->node, &rproc->rvdevs); 367 365 ··· 396 394 * Returns 0 on success, or an appropriate error code otherwise 397 395 */ 398 396 static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, 399 - int avail) 397 + int offset, int avail) 400 398 { 401 399 struct rproc_mem_entry *trace; 402 400 struct device *dev = &rproc->dev; ··· 478 476 * are outside those ranges. 479 477 */ 480 478 static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, 481 - int avail) 479 + int offset, int avail) 482 480 { 483 481 struct rproc_mem_entry *mapping; 484 482 struct device *dev = &rproc->dev; ··· 551 549 * pressure is important; it may have a substantial impact on performance. 552 550 */ 553 551 static int rproc_handle_carveout(struct rproc *rproc, 554 - struct fw_rsc_carveout *rsc, int avail) 552 + struct fw_rsc_carveout *rsc, 553 + int offset, int avail) 554 + 555 555 { 556 556 struct rproc_mem_entry *carveout, *mapping; 557 557 struct device *dev = &rproc->dev; ··· 675 671 return ret; 676 672 } 677 673 674 + static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc, 675 + int offset, int avail) 676 + { 677 + /* Summarize the number of notification IDs */ 678 + rproc->max_notifyid += rsc->num_of_vrings; 679 + 680 + return 0; 681 + } 682 + 678 683 /* 679 684 * A lookup table for resource handlers. The indices are defined in 680 685 * enum fw_resource_type. 681 686 */ 682 - static rproc_handle_resource_t rproc_handle_rsc[] = { 687 + static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { 683 688 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, 684 689 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, 685 690 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, 686 691 [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */ 687 692 }; 688 693 694 + static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { 695 + [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, 696 + }; 697 + 698 + static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = { 699 + [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings, 700 + }; 701 + 689 702 /* handle firmware resource entries before booting the remote processor */ 690 - static int 691 - rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len) 703 + static int rproc_handle_resources(struct rproc *rproc, int len, 704 + rproc_handle_resource_t handlers[RSC_LAST]) 692 705 { 693 706 struct device *dev = &rproc->dev; 694 707 rproc_handle_resource_t handler; 695 708 int ret = 0, i; 696 709 697 - for (i = 0; i < table->num; i++) { 698 - int offset = table->offset[i]; 699 - struct fw_rsc_hdr *hdr = (void *)table + offset; 710 + for (i = 0; i < rproc->table_ptr->num; i++) { 711 + int offset = rproc->table_ptr->offset[i]; 712 + struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; 700 713 int avail = len - offset - sizeof(*hdr); 701 714 void *rsc = (void *)hdr + sizeof(*hdr); 702 715 ··· 730 709 continue; 731 710 } 732 711 733 - handler = rproc_handle_rsc[hdr->type]; 712 + handler = handlers[hdr->type]; 734 713 if (!handler) 735 714 continue; 736 715 737 - ret = handler(rproc, rsc, avail); 738 - if (ret) 739 - break; 740 - } 741 - 742 - return ret; 743 - } 744 - 745 - /* handle firmware resource entries while registering the remote processor */ 746 - static int 747 - rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len) 748 - { 749 - struct device *dev = &rproc->dev; 750 - int ret = 0, i; 751 - 752 - for (i = 0; i < table->num; i++) { 753 - int offset = table->offset[i]; 754 - struct fw_rsc_hdr *hdr = (void *)table + offset; 755 - int avail = len - offset - sizeof(*hdr); 756 - struct fw_rsc_vdev *vrsc; 757 - 758 - /* make sure table isn't truncated */ 759 - if (avail < 0) { 760 - dev_err(dev, "rsc table is truncated\n"); 761 - return -EINVAL; 762 - } 763 - 764 - dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type); 765 - 766 - if (hdr->type != RSC_VDEV) 767 - continue; 768 - 769 - vrsc = (struct fw_rsc_vdev *)hdr->data; 770 - 771 - ret = rproc_handle_vdev(rproc, vrsc, avail); 716 + ret = handler(rproc, rsc, offset + sizeof(*hdr), avail); 772 717 if (ret) 773 718 break; 774 719 } ··· 792 805 { 793 806 struct device *dev = &rproc->dev; 794 807 const char *name = rproc->firmware; 795 - struct resource_table *table; 808 + struct resource_table *table, *loaded_table; 796 809 int ret, tablesz; 810 + 811 + if (!rproc->table_ptr) 812 + return -ENOMEM; 797 813 798 814 ret = rproc_fw_sanity_check(rproc, fw); 799 815 if (ret) ··· 823 833 goto clean_up; 824 834 } 825 835 836 + /* Verify that resource table in loaded fw is unchanged */ 837 + if (rproc->table_csum != crc32(0, table, tablesz)) { 838 + dev_err(dev, "resource checksum failed, fw changed?\n"); 839 + ret = -EINVAL; 840 + goto clean_up; 841 + } 842 + 826 843 /* handle fw resources which are required to boot rproc */ 827 - ret = rproc_handle_boot_rsc(rproc, table, tablesz); 844 + ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers); 828 845 if (ret) { 829 846 dev_err(dev, "Failed to process resources: %d\n", ret); 830 847 goto clean_up; ··· 844 847 goto clean_up; 845 848 } 846 849 850 + /* 851 + * The starting device has been given the rproc->cached_table as the 852 + * resource table. The address of the vring along with the other 853 + * allocated resources (carveouts etc) is stored in cached_table. 854 + * In order to pass this information to the remote device we must 855 + * copy this information to device memory. 856 + */ 857 + loaded_table = rproc_find_loaded_rsc_table(rproc, fw); 858 + if (!loaded_table) 859 + goto clean_up; 860 + 861 + memcpy(loaded_table, rproc->cached_table, tablesz); 862 + 847 863 /* power up the remote processor */ 848 864 ret = rproc->ops->start(rproc); 849 865 if (ret) { 850 866 dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); 851 867 goto clean_up; 852 868 } 869 + 870 + /* 871 + * Update table_ptr so that all subsequent vring allocations and 872 + * virtio fields manipulation update the actual loaded resource table 873 + * in device memory. 874 + */ 875 + rproc->table_ptr = loaded_table; 853 876 854 877 rproc->state = RPROC_RUNNING; 855 878 ··· 905 888 if (!table) 906 889 goto out; 907 890 908 - /* look for virtio devices and register them */ 909 - ret = rproc_handle_virtio_rsc(rproc, table, tablesz); 891 + rproc->table_csum = crc32(0, table, tablesz); 892 + 893 + /* 894 + * Create a copy of the resource table. When a virtio device starts 895 + * and calls vring_new_virtqueue() the address of the allocated vring 896 + * will be stored in the cached_table. Before the device is started, 897 + * cached_table will be copied into devic memory. 898 + */ 899 + rproc->cached_table = kmalloc(tablesz, GFP_KERNEL); 900 + if (!rproc->cached_table) 901 + goto out; 902 + 903 + memcpy(rproc->cached_table, table, tablesz); 904 + rproc->table_ptr = rproc->cached_table; 905 + 906 + /* count the number of notify-ids */ 907 + rproc->max_notifyid = -1; 908 + ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); 910 909 if (ret) 911 910 goto out; 911 + 912 + /* look for virtio devices and register them */ 913 + ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler); 912 914 913 915 out: 914 916 release_firmware(fw); ··· 985 949 986 950 /* wait until there is no more rproc users */ 987 951 wait_for_completion(&rproc->crash_comp); 952 + 953 + /* Free the copy of the resource table */ 954 + kfree(rproc->cached_table); 988 955 989 956 return rproc_add_virtio_devices(rproc); 990 957 } ··· 1144 1105 1145 1106 rproc_disable_iommu(rproc); 1146 1107 1108 + /* Give the next start a clean resource table */ 1109 + rproc->table_ptr = rproc->cached_table; 1110 + 1147 1111 /* if in crash state, unlock crash handler */ 1148 1112 if (rproc->state == RPROC_CRASHED) 1149 1113 complete_all(&rproc->crash_comp); ··· 1238 1196 * @dev: the underlying device 1239 1197 * @name: name of this remote processor 1240 1198 * @ops: platform-specific handlers (mainly start/stop) 1241 - * @firmware: name of firmware file to load 1199 + * @firmware: name of firmware file to load, can be NULL 1242 1200 * @len: length of private data needed by the rproc driver (in bytes) 1243 1201 * 1244 1202 * Allocates a new remote processor handle, but does not register 1245 - * it yet. 1203 + * it yet. if @firmware is NULL, a default name is used. 1246 1204 * 1247 1205 * This function should be used by rproc implementations during initialization 1248 1206 * of the remote processor. ··· 1261 1219 const char *firmware, int len) 1262 1220 { 1263 1221 struct rproc *rproc; 1222 + char *p, *template = "rproc-%s-fw"; 1223 + int name_len = 0; 1264 1224 1265 1225 if (!dev || !name || !ops) 1266 1226 return NULL; 1267 1227 1268 - rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL); 1228 + if (!firmware) 1229 + /* 1230 + * Make room for default firmware name (minus %s plus '\0'). 1231 + * If the caller didn't pass in a firmware name then 1232 + * construct a default name. We're already glomming 'len' 1233 + * bytes onto the end of the struct rproc allocation, so do 1234 + * a few more for the default firmware name (but only if 1235 + * the caller doesn't pass one). 1236 + */ 1237 + name_len = strlen(name) + strlen(template) - 2 + 1; 1238 + 1239 + rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL); 1269 1240 if (!rproc) { 1270 1241 dev_err(dev, "%s: kzalloc failed\n", __func__); 1271 1242 return NULL; 1272 1243 } 1273 1244 1245 + if (!firmware) { 1246 + p = (char *)rproc + sizeof(struct rproc) + len; 1247 + snprintf(p, name_len, template, name); 1248 + } else { 1249 + p = (char *)firmware; 1250 + } 1251 + 1252 + rproc->firmware = p; 1274 1253 rproc->name = name; 1275 1254 rproc->ops = ops; 1276 - rproc->firmware = firmware; 1277 1255 rproc->priv = &rproc[1]; 1278 1256 1279 1257 device_initialize(&rproc->dev); ··· 1376 1314 /* clean up remote vdev entries */ 1377 1315 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) 1378 1316 rproc_remove_virtio_dev(rvdev); 1317 + 1318 + /* Free the copy of the resource table */ 1319 + kfree(rproc->cached_table); 1379 1320 1380 1321 device_del(&rproc->dev); 1381 1322
+72 -30
drivers/remoteproc/remoteproc_elf_loader.c
··· 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; 232 - const char *name_table; 233 - struct device *dev = &rproc->dev; 234 - struct resource_table *table = NULL; 235 215 int i; 236 - const u8 *elf_data = fw->data; 216 + const char *name_table; 217 + struct resource_table *table = NULL; 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; ··· 231 250 table = (struct resource_table *)(elf_data + offset); 232 251 233 252 /* make sure we have the entire table */ 234 - if (offset + size > fw->size) { 253 + if (offset + size > fw_size || offset + size < size) { 235 254 dev_err(dev, "resource table truncated\n"); 236 255 return NULL; 237 256 } ··· 261 280 return NULL; 262 281 } 263 282 264 - *tablesz = shdr->sh_size; 265 - break; 283 + return shdr; 266 284 } 267 285 286 + return NULL; 287 + } 288 + 289 + /** 290 + * rproc_elf_find_rsc_table() - find the resource table 291 + * @rproc: the rproc handle 292 + * @fw: the ELF firmware image 293 + * @tablesz: place holder for providing back the table size 294 + * 295 + * This function finds the resource table inside the remote processor's 296 + * firmware. It is used both upon the registration of @rproc (in order 297 + * to look for and register the supported virito devices), and when the 298 + * @rproc is booted. 299 + * 300 + * Returns the pointer to the resource table if it is found, and write its 301 + * size into @tablesz. If a valid table isn't found, NULL is returned 302 + * (and @tablesz isn't set). 303 + */ 304 + static struct resource_table * 305 + rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, 306 + int *tablesz) 307 + { 308 + struct elf32_hdr *ehdr; 309 + struct elf32_shdr *shdr; 310 + struct device *dev = &rproc->dev; 311 + struct resource_table *table = NULL; 312 + const u8 *elf_data = fw->data; 313 + 314 + ehdr = (struct elf32_hdr *)elf_data; 315 + 316 + shdr = find_table(dev, ehdr, fw->size); 317 + if (!shdr) 318 + return NULL; 319 + 320 + table = (struct resource_table *)(elf_data + shdr->sh_offset); 321 + *tablesz = shdr->sh_size; 322 + 268 323 return table; 324 + } 325 + 326 + /** 327 + * rproc_elf_find_loaded_rsc_table() - find the loaded resource table 328 + * @rproc: the rproc handle 329 + * @fw: the ELF firmware image 330 + * 331 + * This function finds the location of the loaded resource table. Don't 332 + * call this function if the table wasn't loaded yet - it's a bug if you do. 333 + * 334 + * Returns the pointer to the resource table if it is found or NULL otherwise. 335 + * If the table wasn't loaded yet the result is unspecified. 336 + */ 337 + static struct resource_table * 338 + rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw) 339 + { 340 + struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data; 341 + struct elf32_shdr *shdr; 342 + 343 + shdr = find_table(&rproc->dev, ehdr, fw->size); 344 + if (!shdr) 345 + return NULL; 346 + 347 + return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size); 269 348 } 270 349 271 350 const struct rproc_fw_ops rproc_elf_fw_ops = { 272 351 .load = rproc_elf_load_segments, 273 352 .find_rsc_table = rproc_elf_find_rsc_table, 353 + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, 274 354 .sanity_check = rproc_elf_sanity_check, 275 355 .get_boot_addr = rproc_elf_get_boot_addr 276 356 };
+14 -1
drivers/remoteproc/remoteproc_internal.h
··· 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 ··· 38 37 struct resource_table *(*find_rsc_table) (struct rproc *rproc, 39 38 const struct firmware *fw, 40 39 int *tablesz); 40 + struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc, 41 + const struct firmware *fw); 41 42 int (*load)(struct rproc *rproc, const struct firmware *fw); 42 43 int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); 43 44 u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); ··· 103 100 return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz); 104 101 105 102 return NULL; 103 + } 104 + 105 + static inline 106 + struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc, 107 + const struct firmware *fw) 108 + { 109 + if (rproc->fw_ops->find_loaded_rsc_table) 110 + return rproc->fw_ops->find_loaded_rsc_table(rproc, fw); 111 + 112 + return NULL; 106 113 } 107 114 108 115 extern const struct rproc_fw_ops rproc_elf_fw_ops;
+64 -15
drivers/remoteproc/remoteproc_virtio.c
··· 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 ··· 209 199 static u32 rproc_virtio_get_features(struct virtio_device *vdev) 210 200 { 211 201 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); 202 + struct fw_rsc_vdev *rsc; 212 203 213 - return rvdev->dfeatures; 204 + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; 205 + 206 + return rsc->dfeatures; 214 207 } 215 208 216 209 static void rproc_virtio_finalize_features(struct virtio_device *vdev) 217 210 { 218 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; 219 215 220 216 /* Give virtio_ring a chance to accept features */ 221 217 vring_transport_features(vdev); ··· 229 213 /* 230 214 * Remember the finalized features of our vdev, and provide it 231 215 * to the remote processor once it is powered on. 232 - * 233 - * Similarly to the status field, we don't expose yet the negotiated 234 - * features to the remote processors at this point. This will be 235 - * fixed as part of a small resource table overhaul and then an 236 - * extension of the virtio resource entries. 237 216 */ 238 - rvdev->gfeatures = vdev->features[0]; 217 + rsc->gfeatures = vdev->features[0]; 218 + } 219 + 220 + static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, 221 + void *buf, unsigned len) 222 + { 223 + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); 224 + struct fw_rsc_vdev *rsc; 225 + void *cfg; 226 + 227 + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; 228 + cfg = &rsc->vring[rsc->num_of_vrings]; 229 + 230 + if (offset + len > rsc->config_len || offset + len < len) { 231 + dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n"); 232 + return; 233 + } 234 + 235 + memcpy(buf, cfg + offset, len); 236 + } 237 + 238 + static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset, 239 + const void *buf, unsigned len) 240 + { 241 + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); 242 + struct fw_rsc_vdev *rsc; 243 + void *cfg; 244 + 245 + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; 246 + cfg = &rsc->vring[rsc->num_of_vrings]; 247 + 248 + if (offset + len > rsc->config_len || offset + len < len) { 249 + dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n"); 250 + return; 251 + } 252 + 253 + memcpy(cfg + offset, buf, len); 239 254 } 240 255 241 256 static const struct virtio_config_ops rproc_virtio_config_ops = { ··· 277 230 .reset = rproc_virtio_reset, 278 231 .set_status = rproc_virtio_set_status, 279 232 .get_status = rproc_virtio_get_status, 233 + .get = rproc_virtio_get, 234 + .set = rproc_virtio_set, 280 235 }; 281 236 282 237 /*
+30 -15
drivers/remoteproc/ste_modem_rproc.c
··· 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; 71 - 72 - if (!fw) 73 - return NULL; 74 - 75 - toc = (void *)fw->data; 70 + const struct ste_toc *toc; 71 + toc = data; 76 72 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; ··· 88 96 { 89 97 struct sproc *sproc = rproc->priv; 90 98 struct resource_table *table; 91 - struct ste_toc_entry *entry; 99 + const struct ste_toc_entry *entry; 92 100 93 - entry = sproc_find_rsc_entry(fw); 101 + if (!fw) 102 + return NULL; 103 + 104 + entry = sproc_find_rsc_entry(fw->data); 94 105 if (!entry) { 95 106 sproc_err(sproc, "resource table not found in fw\n"); 96 107 return NULL; ··· 144 149 return table; 145 150 } 146 151 152 + /* Find the resource table inside the remote processor's firmware. */ 153 + static struct resource_table * 154 + sproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw) 155 + { 156 + struct sproc *sproc = rproc->priv; 157 + const struct ste_toc_entry *entry; 158 + 159 + if (!fw || !sproc->fw_addr) 160 + return NULL; 161 + 162 + entry = sproc_find_rsc_entry(sproc->fw_addr); 163 + if (!entry) { 164 + sproc_err(sproc, "resource table not found in fw\n"); 165 + return NULL; 166 + } 167 + 168 + return sproc->fw_addr + entry->start; 169 + } 170 + 147 171 /* STE modem firmware handler operations */ 148 172 const struct rproc_fw_ops sproc_fw_ops = { 149 173 .load = sproc_load_segments, 150 174 .find_rsc_table = sproc_find_rsc_table, 175 + .find_loaded_rsc_table = sproc_find_loaded_rsc_table, 151 176 }; 152 177 153 178 /* Kick the modem with specified notification id */ ··· 213 198 } 214 199 215 200 /* Subscribe to notifications */ 216 - for (i = 0; i < rproc->max_notifyid; i++) { 201 + for (i = 0; i <= rproc->max_notifyid; i++) { 217 202 err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i); 218 203 if (err) { 219 204 sproc_err(sproc,
+9 -4
include/linux/remoteproc.h
··· 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; ··· 432 429 struct completion crash_comp; 433 430 bool recovery_disabled; 434 431 int max_notifyid; 432 + struct resource_table *table_ptr; 433 + struct resource_table *cached_table; 434 + u32 table_csum; 435 435 }; 436 436 437 437 /* we currently support only two vrings per rvdev */ 438 + 438 439 #define RVDEV_NUM_VRINGS 2 439 440 440 441 /** ··· 469 462 * @rproc: the rproc handle 470 463 * @vdev: the virio device 471 464 * @vring: the vrings for this vdev 472 - * @dfeatures: virtio device features 473 - * @gfeatures: virtio guest features 465 + * @rsc_offset: offset of the vdev's resource entry 474 466 */ 475 467 struct rproc_vdev { 476 468 struct list_head node; 477 469 struct rproc *rproc; 478 470 struct virtio_device vdev; 479 471 struct rproc_vring vring[RVDEV_NUM_VRINGS]; 480 - unsigned long dfeatures; 481 - unsigned long gfeatures; 472 + u32 rsc_offset; 482 473 }; 483 474 484 475 struct rproc *rproc_alloc(struct device *dev, const char *name,