1*400e64dfSOhad Ben-Cohen /* 2*400e64dfSOhad Ben-Cohen * Remote Processor Framework 3*400e64dfSOhad Ben-Cohen * 4*400e64dfSOhad Ben-Cohen * Copyright (C) 2011 Texas Instruments, Inc. 5*400e64dfSOhad Ben-Cohen * Copyright (C) 2011 Google, Inc. 6*400e64dfSOhad Ben-Cohen * 7*400e64dfSOhad Ben-Cohen * Ohad Ben-Cohen <ohad@wizery.com> 8*400e64dfSOhad Ben-Cohen * Brian Swetland <swetland@google.com> 9*400e64dfSOhad Ben-Cohen * Mark Grosen <mgrosen@ti.com> 10*400e64dfSOhad Ben-Cohen * Fernando Guzman Lugo <fernando.lugo@ti.com> 11*400e64dfSOhad Ben-Cohen * Suman Anna <s-anna@ti.com> 12*400e64dfSOhad Ben-Cohen * Robert Tivy <rtivy@ti.com> 13*400e64dfSOhad Ben-Cohen * Armando Uribe De Leon <x0095078@ti.com> 14*400e64dfSOhad Ben-Cohen * 15*400e64dfSOhad Ben-Cohen * This program is free software; you can redistribute it and/or 16*400e64dfSOhad Ben-Cohen * modify it under the terms of the GNU General Public License 17*400e64dfSOhad Ben-Cohen * version 2 as published by the Free Software Foundation. 18*400e64dfSOhad Ben-Cohen * 19*400e64dfSOhad Ben-Cohen * This program is distributed in the hope that it will be useful, 20*400e64dfSOhad Ben-Cohen * but WITHOUT ANY WARRANTY; without even the implied warranty of 21*400e64dfSOhad Ben-Cohen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22*400e64dfSOhad Ben-Cohen * GNU General Public License for more details. 23*400e64dfSOhad Ben-Cohen */ 24*400e64dfSOhad Ben-Cohen 25*400e64dfSOhad Ben-Cohen #define pr_fmt(fmt) "%s: " fmt, __func__ 26*400e64dfSOhad Ben-Cohen 27*400e64dfSOhad Ben-Cohen #include <linux/kernel.h> 28*400e64dfSOhad Ben-Cohen #include <linux/module.h> 29*400e64dfSOhad Ben-Cohen #include <linux/device.h> 30*400e64dfSOhad Ben-Cohen #include <linux/slab.h> 31*400e64dfSOhad Ben-Cohen #include <linux/mutex.h> 32*400e64dfSOhad Ben-Cohen #include <linux/dma-mapping.h> 33*400e64dfSOhad Ben-Cohen #include <linux/firmware.h> 34*400e64dfSOhad Ben-Cohen #include <linux/string.h> 35*400e64dfSOhad Ben-Cohen #include <linux/debugfs.h> 36*400e64dfSOhad Ben-Cohen #include <linux/remoteproc.h> 37*400e64dfSOhad Ben-Cohen #include <linux/iommu.h> 38*400e64dfSOhad Ben-Cohen #include <linux/klist.h> 39*400e64dfSOhad Ben-Cohen #include <linux/elf.h> 40*400e64dfSOhad Ben-Cohen #include <linux/virtio_ids.h> 41*400e64dfSOhad Ben-Cohen #include <linux/virtio_ring.h> 42*400e64dfSOhad Ben-Cohen 43*400e64dfSOhad Ben-Cohen #include "remoteproc_internal.h" 44*400e64dfSOhad Ben-Cohen 45*400e64dfSOhad Ben-Cohen static void klist_rproc_get(struct klist_node *n); 46*400e64dfSOhad Ben-Cohen static void klist_rproc_put(struct klist_node *n); 47*400e64dfSOhad Ben-Cohen 48*400e64dfSOhad Ben-Cohen /* 49*400e64dfSOhad Ben-Cohen * klist of the available remote processors. 50*400e64dfSOhad Ben-Cohen * 51*400e64dfSOhad Ben-Cohen * We need this in order to support name-based lookups (needed by the 52*400e64dfSOhad Ben-Cohen * rproc_get_by_name()). 53*400e64dfSOhad Ben-Cohen * 54*400e64dfSOhad Ben-Cohen * That said, we don't use rproc_get_by_name() anymore within the rpmsg 55*400e64dfSOhad Ben-Cohen * framework. The use cases that do require its existence should be 56*400e64dfSOhad Ben-Cohen * scrutinized, and hopefully migrated to rproc_boot() using device-based 57*400e64dfSOhad Ben-Cohen * binding. 58*400e64dfSOhad Ben-Cohen * 59*400e64dfSOhad Ben-Cohen * If/when this materializes, we could drop the klist (and the by_name 60*400e64dfSOhad Ben-Cohen * API). 61*400e64dfSOhad Ben-Cohen */ 62*400e64dfSOhad Ben-Cohen static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put); 63*400e64dfSOhad Ben-Cohen 64*400e64dfSOhad Ben-Cohen typedef int (*rproc_handle_resources_t)(struct rproc *rproc, 65*400e64dfSOhad Ben-Cohen struct fw_resource *rsc, int len); 66*400e64dfSOhad Ben-Cohen 67*400e64dfSOhad Ben-Cohen /* 68*400e64dfSOhad Ben-Cohen * This is the IOMMU fault handler we register with the IOMMU API 69*400e64dfSOhad Ben-Cohen * (when relevant; not all remote processors access memory through 70*400e64dfSOhad Ben-Cohen * an IOMMU). 71*400e64dfSOhad Ben-Cohen * 72*400e64dfSOhad Ben-Cohen * IOMMU core will invoke this handler whenever the remote processor 73*400e64dfSOhad Ben-Cohen * will try to access an unmapped device address. 74*400e64dfSOhad Ben-Cohen * 75*400e64dfSOhad Ben-Cohen * Currently this is mostly a stub, but it will be later used to trigger 76*400e64dfSOhad Ben-Cohen * the recovery of the remote processor. 77*400e64dfSOhad Ben-Cohen */ 78*400e64dfSOhad Ben-Cohen static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, 79*400e64dfSOhad Ben-Cohen unsigned long iova, int flags) 80*400e64dfSOhad Ben-Cohen { 81*400e64dfSOhad Ben-Cohen dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); 82*400e64dfSOhad Ben-Cohen 83*400e64dfSOhad Ben-Cohen /* 84*400e64dfSOhad Ben-Cohen * Let the iommu core know we're not really handling this fault; 85*400e64dfSOhad Ben-Cohen * we just plan to use this as a recovery trigger. 86*400e64dfSOhad Ben-Cohen */ 87*400e64dfSOhad Ben-Cohen return -ENOSYS; 88*400e64dfSOhad Ben-Cohen } 89*400e64dfSOhad Ben-Cohen 90*400e64dfSOhad Ben-Cohen static int rproc_enable_iommu(struct rproc *rproc) 91*400e64dfSOhad Ben-Cohen { 92*400e64dfSOhad Ben-Cohen struct iommu_domain *domain; 93*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 94*400e64dfSOhad Ben-Cohen int ret; 95*400e64dfSOhad Ben-Cohen 96*400e64dfSOhad Ben-Cohen /* 97*400e64dfSOhad Ben-Cohen * We currently use iommu_present() to decide if an IOMMU 98*400e64dfSOhad Ben-Cohen * setup is needed. 99*400e64dfSOhad Ben-Cohen * 100*400e64dfSOhad Ben-Cohen * This works for simple cases, but will easily fail with 101*400e64dfSOhad Ben-Cohen * platforms that do have an IOMMU, but not for this specific 102*400e64dfSOhad Ben-Cohen * rproc. 103*400e64dfSOhad Ben-Cohen * 104*400e64dfSOhad Ben-Cohen * This will be easily solved by introducing hw capabilities 105*400e64dfSOhad Ben-Cohen * that will be set by the remoteproc driver. 106*400e64dfSOhad Ben-Cohen */ 107*400e64dfSOhad Ben-Cohen if (!iommu_present(dev->bus)) { 108*400e64dfSOhad Ben-Cohen dev_err(dev, "iommu not found\n"); 109*400e64dfSOhad Ben-Cohen return -ENODEV; 110*400e64dfSOhad Ben-Cohen } 111*400e64dfSOhad Ben-Cohen 112*400e64dfSOhad Ben-Cohen domain = iommu_domain_alloc(dev->bus); 113*400e64dfSOhad Ben-Cohen if (!domain) { 114*400e64dfSOhad Ben-Cohen dev_err(dev, "can't alloc iommu domain\n"); 115*400e64dfSOhad Ben-Cohen return -ENOMEM; 116*400e64dfSOhad Ben-Cohen } 117*400e64dfSOhad Ben-Cohen 118*400e64dfSOhad Ben-Cohen iommu_set_fault_handler(domain, rproc_iommu_fault); 119*400e64dfSOhad Ben-Cohen 120*400e64dfSOhad Ben-Cohen ret = iommu_attach_device(domain, dev); 121*400e64dfSOhad Ben-Cohen if (ret) { 122*400e64dfSOhad Ben-Cohen dev_err(dev, "can't attach iommu device: %d\n", ret); 123*400e64dfSOhad Ben-Cohen goto free_domain; 124*400e64dfSOhad Ben-Cohen } 125*400e64dfSOhad Ben-Cohen 126*400e64dfSOhad Ben-Cohen rproc->domain = domain; 127*400e64dfSOhad Ben-Cohen 128*400e64dfSOhad Ben-Cohen return 0; 129*400e64dfSOhad Ben-Cohen 130*400e64dfSOhad Ben-Cohen free_domain: 131*400e64dfSOhad Ben-Cohen iommu_domain_free(domain); 132*400e64dfSOhad Ben-Cohen return ret; 133*400e64dfSOhad Ben-Cohen } 134*400e64dfSOhad Ben-Cohen 135*400e64dfSOhad Ben-Cohen static void rproc_disable_iommu(struct rproc *rproc) 136*400e64dfSOhad Ben-Cohen { 137*400e64dfSOhad Ben-Cohen struct iommu_domain *domain = rproc->domain; 138*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 139*400e64dfSOhad Ben-Cohen 140*400e64dfSOhad Ben-Cohen if (!domain) 141*400e64dfSOhad Ben-Cohen return; 142*400e64dfSOhad Ben-Cohen 143*400e64dfSOhad Ben-Cohen iommu_detach_device(domain, dev); 144*400e64dfSOhad Ben-Cohen iommu_domain_free(domain); 145*400e64dfSOhad Ben-Cohen 146*400e64dfSOhad Ben-Cohen return; 147*400e64dfSOhad Ben-Cohen } 148*400e64dfSOhad Ben-Cohen 149*400e64dfSOhad Ben-Cohen /* 150*400e64dfSOhad Ben-Cohen * Some remote processors will ask us to allocate them physically contiguous 151*400e64dfSOhad Ben-Cohen * memory regions (which we call "carveouts"), and map them to specific 152*400e64dfSOhad Ben-Cohen * device addresses (which are hardcoded in the firmware). 153*400e64dfSOhad Ben-Cohen * 154*400e64dfSOhad Ben-Cohen * They may then ask us to copy objects into specific device addresses (e.g. 155*400e64dfSOhad Ben-Cohen * code/data sections) or expose us certain symbols in other device address 156*400e64dfSOhad Ben-Cohen * (e.g. their trace buffer). 157*400e64dfSOhad Ben-Cohen * 158*400e64dfSOhad Ben-Cohen * This function is an internal helper with which we can go over the allocated 159*400e64dfSOhad Ben-Cohen * carveouts and translate specific device address to kernel virtual addresses 160*400e64dfSOhad Ben-Cohen * so we can access the referenced memory. 161*400e64dfSOhad Ben-Cohen * 162*400e64dfSOhad Ben-Cohen * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, 163*400e64dfSOhad Ben-Cohen * but only on kernel direct mapped RAM memory. Instead, we're just using 164*400e64dfSOhad Ben-Cohen * here the output of the DMA API, which should be more correct. 165*400e64dfSOhad Ben-Cohen */ 166*400e64dfSOhad Ben-Cohen static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) 167*400e64dfSOhad Ben-Cohen { 168*400e64dfSOhad Ben-Cohen struct rproc_mem_entry *carveout; 169*400e64dfSOhad Ben-Cohen void *ptr = NULL; 170*400e64dfSOhad Ben-Cohen 171*400e64dfSOhad Ben-Cohen list_for_each_entry(carveout, &rproc->carveouts, node) { 172*400e64dfSOhad Ben-Cohen int offset = da - carveout->da; 173*400e64dfSOhad Ben-Cohen 174*400e64dfSOhad Ben-Cohen /* try next carveout if da is too small */ 175*400e64dfSOhad Ben-Cohen if (offset < 0) 176*400e64dfSOhad Ben-Cohen continue; 177*400e64dfSOhad Ben-Cohen 178*400e64dfSOhad Ben-Cohen /* try next carveout if da is too large */ 179*400e64dfSOhad Ben-Cohen if (offset + len > carveout->len) 180*400e64dfSOhad Ben-Cohen continue; 181*400e64dfSOhad Ben-Cohen 182*400e64dfSOhad Ben-Cohen ptr = carveout->va + offset; 183*400e64dfSOhad Ben-Cohen 184*400e64dfSOhad Ben-Cohen break; 185*400e64dfSOhad Ben-Cohen } 186*400e64dfSOhad Ben-Cohen 187*400e64dfSOhad Ben-Cohen return ptr; 188*400e64dfSOhad Ben-Cohen } 189*400e64dfSOhad Ben-Cohen 190*400e64dfSOhad Ben-Cohen /** 191*400e64dfSOhad Ben-Cohen * rproc_load_segments() - load firmware segments to memory 192*400e64dfSOhad Ben-Cohen * @rproc: remote processor which will be booted using these fw segments 193*400e64dfSOhad Ben-Cohen * @elf_data: the content of the ELF firmware image 194*400e64dfSOhad Ben-Cohen * 195*400e64dfSOhad Ben-Cohen * This function loads the firmware segments to memory, where the remote 196*400e64dfSOhad Ben-Cohen * processor expects them. 197*400e64dfSOhad Ben-Cohen * 198*400e64dfSOhad Ben-Cohen * Some remote processors will expect their code and data to be placed 199*400e64dfSOhad Ben-Cohen * in specific device addresses, and can't have them dynamically assigned. 200*400e64dfSOhad Ben-Cohen * 201*400e64dfSOhad Ben-Cohen * We currently support only those kind of remote processors, and expect 202*400e64dfSOhad Ben-Cohen * the program header's paddr member to contain those addresses. We then go 203*400e64dfSOhad Ben-Cohen * through the physically contiguous "carveout" memory regions which we 204*400e64dfSOhad Ben-Cohen * allocated (and mapped) earlier on behalf of the remote processor, 205*400e64dfSOhad Ben-Cohen * and "translate" device address to kernel addresses, so we can copy the 206*400e64dfSOhad Ben-Cohen * segments where they are expected. 207*400e64dfSOhad Ben-Cohen * 208*400e64dfSOhad Ben-Cohen * Currently we only support remote processors that required carveout 209*400e64dfSOhad Ben-Cohen * allocations and got them mapped onto their iommus. Some processors 210*400e64dfSOhad Ben-Cohen * might be different: they might not have iommus, and would prefer to 211*400e64dfSOhad Ben-Cohen * directly allocate memory for every segment/resource. This is not yet 212*400e64dfSOhad Ben-Cohen * supported, though. 213*400e64dfSOhad Ben-Cohen */ 214*400e64dfSOhad Ben-Cohen static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data) 215*400e64dfSOhad Ben-Cohen { 216*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 217*400e64dfSOhad Ben-Cohen struct elf32_hdr *ehdr; 218*400e64dfSOhad Ben-Cohen struct elf32_phdr *phdr; 219*400e64dfSOhad Ben-Cohen int i, ret = 0; 220*400e64dfSOhad Ben-Cohen 221*400e64dfSOhad Ben-Cohen ehdr = (struct elf32_hdr *)elf_data; 222*400e64dfSOhad Ben-Cohen phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); 223*400e64dfSOhad Ben-Cohen 224*400e64dfSOhad Ben-Cohen /* go through the available ELF segments */ 225*400e64dfSOhad Ben-Cohen for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 226*400e64dfSOhad Ben-Cohen u32 da = phdr->p_paddr; 227*400e64dfSOhad Ben-Cohen u32 memsz = phdr->p_memsz; 228*400e64dfSOhad Ben-Cohen u32 filesz = phdr->p_filesz; 229*400e64dfSOhad Ben-Cohen void *ptr; 230*400e64dfSOhad Ben-Cohen 231*400e64dfSOhad Ben-Cohen if (phdr->p_type != PT_LOAD) 232*400e64dfSOhad Ben-Cohen continue; 233*400e64dfSOhad Ben-Cohen 234*400e64dfSOhad Ben-Cohen dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", 235*400e64dfSOhad Ben-Cohen phdr->p_type, da, memsz, filesz); 236*400e64dfSOhad Ben-Cohen 237*400e64dfSOhad Ben-Cohen if (filesz > memsz) { 238*400e64dfSOhad Ben-Cohen dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", 239*400e64dfSOhad Ben-Cohen filesz, memsz); 240*400e64dfSOhad Ben-Cohen ret = -EINVAL; 241*400e64dfSOhad Ben-Cohen break; 242*400e64dfSOhad Ben-Cohen } 243*400e64dfSOhad Ben-Cohen 244*400e64dfSOhad Ben-Cohen /* grab the kernel address for this device address */ 245*400e64dfSOhad Ben-Cohen ptr = rproc_da_to_va(rproc, da, memsz); 246*400e64dfSOhad Ben-Cohen if (!ptr) { 247*400e64dfSOhad Ben-Cohen dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); 248*400e64dfSOhad Ben-Cohen ret = -EINVAL; 249*400e64dfSOhad Ben-Cohen break; 250*400e64dfSOhad Ben-Cohen } 251*400e64dfSOhad Ben-Cohen 252*400e64dfSOhad Ben-Cohen /* put the segment where the remote processor expects it */ 253*400e64dfSOhad Ben-Cohen if (phdr->p_filesz) 254*400e64dfSOhad Ben-Cohen memcpy(ptr, elf_data + phdr->p_offset, filesz); 255*400e64dfSOhad Ben-Cohen 256*400e64dfSOhad Ben-Cohen /* 257*400e64dfSOhad Ben-Cohen * Zero out remaining memory for this segment. 258*400e64dfSOhad Ben-Cohen * 259*400e64dfSOhad Ben-Cohen * This isn't strictly required since dma_alloc_coherent already 260*400e64dfSOhad Ben-Cohen * did this for us. albeit harmless, we may consider removing 261*400e64dfSOhad Ben-Cohen * this. 262*400e64dfSOhad Ben-Cohen */ 263*400e64dfSOhad Ben-Cohen if (memsz > filesz) 264*400e64dfSOhad Ben-Cohen memset(ptr + filesz, 0, memsz - filesz); 265*400e64dfSOhad Ben-Cohen } 266*400e64dfSOhad Ben-Cohen 267*400e64dfSOhad Ben-Cohen return ret; 268*400e64dfSOhad Ben-Cohen } 269*400e64dfSOhad Ben-Cohen 270*400e64dfSOhad Ben-Cohen /** 271*400e64dfSOhad Ben-Cohen * rproc_handle_virtio_hdr() - handle a virtio header resource 272*400e64dfSOhad Ben-Cohen * @rproc: the remote processor 273*400e64dfSOhad Ben-Cohen * @rsc: the resource descriptor 274*400e64dfSOhad Ben-Cohen * 275*400e64dfSOhad Ben-Cohen * The existence of this virtio hdr resource entry means that the firmware 276*400e64dfSOhad Ben-Cohen * of this @rproc supports this virtio device. 277*400e64dfSOhad Ben-Cohen * 278*400e64dfSOhad Ben-Cohen * Currently we support only a single virtio device of type VIRTIO_ID_RPMSG, 279*400e64dfSOhad Ben-Cohen * but the plan is to remove this limitation and support any number 280*400e64dfSOhad Ben-Cohen * of virtio devices (and of any type). We'll also add support for dynamically 281*400e64dfSOhad Ben-Cohen * adding (and removing) virtio devices over the rpmsg bus, but small 282*400e64dfSOhad Ben-Cohen * firmwares that doesn't want to get involved with rpmsg will be able 283*400e64dfSOhad Ben-Cohen * to simple use the resource table for this. 284*400e64dfSOhad Ben-Cohen * 285*400e64dfSOhad Ben-Cohen * At this point this virtio header entry is rather simple: it just 286*400e64dfSOhad Ben-Cohen * announces the virtio device id and the supported virtio device features. 287*400e64dfSOhad Ben-Cohen * The plan though is to extend this to include the vring information and 288*400e64dfSOhad Ben-Cohen * the virtio config space, too (but first, some resource table overhaul 289*400e64dfSOhad Ben-Cohen * is needed: move from fixed-sized to variable-length TLV entries). 290*400e64dfSOhad Ben-Cohen * 291*400e64dfSOhad Ben-Cohen * For now, the 'flags' member of the resource entry contains the virtio 292*400e64dfSOhad Ben-Cohen * device id, the 'da' member contains the device features, and 'pa' is 293*400e64dfSOhad Ben-Cohen * where we need to store the guest features once negotiation completes. 294*400e64dfSOhad Ben-Cohen * As usual, the 'id' member of this resource contains the index of this 295*400e64dfSOhad Ben-Cohen * resource type (i.e. is this the first virtio hdr entry, the 2nd, ...). 296*400e64dfSOhad Ben-Cohen * 297*400e64dfSOhad Ben-Cohen * Returns 0 on success, or an appropriate error code otherwise 298*400e64dfSOhad Ben-Cohen */ 299*400e64dfSOhad Ben-Cohen static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc) 300*400e64dfSOhad Ben-Cohen { 301*400e64dfSOhad Ben-Cohen struct rproc_vdev *rvdev; 302*400e64dfSOhad Ben-Cohen 303*400e64dfSOhad Ben-Cohen /* we only support VIRTIO_ID_RPMSG devices for now */ 304*400e64dfSOhad Ben-Cohen if (rsc->flags != VIRTIO_ID_RPMSG) { 305*400e64dfSOhad Ben-Cohen dev_warn(rproc->dev, "unsupported vdev: %d\n", rsc->flags); 306*400e64dfSOhad Ben-Cohen return -EINVAL; 307*400e64dfSOhad Ben-Cohen } 308*400e64dfSOhad Ben-Cohen 309*400e64dfSOhad Ben-Cohen /* we only support a single vdev per rproc for now */ 310*400e64dfSOhad Ben-Cohen if (rsc->id || rproc->rvdev) { 311*400e64dfSOhad Ben-Cohen dev_warn(rproc->dev, "redundant vdev entry: %s\n", rsc->name); 312*400e64dfSOhad Ben-Cohen return -EINVAL; 313*400e64dfSOhad Ben-Cohen } 314*400e64dfSOhad Ben-Cohen 315*400e64dfSOhad Ben-Cohen rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL); 316*400e64dfSOhad Ben-Cohen if (!rvdev) 317*400e64dfSOhad Ben-Cohen return -ENOMEM; 318*400e64dfSOhad Ben-Cohen 319*400e64dfSOhad Ben-Cohen /* remember the device features */ 320*400e64dfSOhad Ben-Cohen rvdev->dfeatures = rsc->da; 321*400e64dfSOhad Ben-Cohen 322*400e64dfSOhad Ben-Cohen rproc->rvdev = rvdev; 323*400e64dfSOhad Ben-Cohen rvdev->rproc = rproc; 324*400e64dfSOhad Ben-Cohen 325*400e64dfSOhad Ben-Cohen return 0; 326*400e64dfSOhad Ben-Cohen } 327*400e64dfSOhad Ben-Cohen 328*400e64dfSOhad Ben-Cohen /** 329*400e64dfSOhad Ben-Cohen * rproc_handle_vring() - handle a vring fw resource 330*400e64dfSOhad Ben-Cohen * @rproc: the remote processor 331*400e64dfSOhad Ben-Cohen * @rsc: the vring resource descriptor 332*400e64dfSOhad Ben-Cohen * 333*400e64dfSOhad Ben-Cohen * This resource entry requires allocation of non-cacheable memory 334*400e64dfSOhad Ben-Cohen * for a virtio vring. Currently we only support two vrings per remote 335*400e64dfSOhad Ben-Cohen * processor, required for the virtio rpmsg device. 336*400e64dfSOhad Ben-Cohen * 337*400e64dfSOhad Ben-Cohen * The 'len' member of @rsc should contain the number of buffers this vring 338*400e64dfSOhad Ben-Cohen * support and 'da' should either contain the device address where 339*400e64dfSOhad Ben-Cohen * the remote processor is expecting the vring, or indicate that 340*400e64dfSOhad Ben-Cohen * dynamically allocation of the vring's device address is supported. 341*400e64dfSOhad Ben-Cohen * 342*400e64dfSOhad Ben-Cohen * Note: 'da' is currently not handled. This will be revised when the generic 343*400e64dfSOhad Ben-Cohen * iommu-based DMA API will arrive, or a dynanic & non-iommu use case show 344*400e64dfSOhad Ben-Cohen * up. Meanwhile, statically-addressed iommu-based images should use 345*400e64dfSOhad Ben-Cohen * RSC_DEVMEM resource entries to map their require 'da' to the physical 346*400e64dfSOhad Ben-Cohen * address of their base CMA region. 347*400e64dfSOhad Ben-Cohen * 348*400e64dfSOhad Ben-Cohen * Returns 0 on success, or an appropriate error code otherwise 349*400e64dfSOhad Ben-Cohen */ 350*400e64dfSOhad Ben-Cohen static int rproc_handle_vring(struct rproc *rproc, struct fw_resource *rsc) 351*400e64dfSOhad Ben-Cohen { 352*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 353*400e64dfSOhad Ben-Cohen struct rproc_vdev *rvdev = rproc->rvdev; 354*400e64dfSOhad Ben-Cohen dma_addr_t dma; 355*400e64dfSOhad Ben-Cohen int size, id = rsc->id; 356*400e64dfSOhad Ben-Cohen void *va; 357*400e64dfSOhad Ben-Cohen 358*400e64dfSOhad Ben-Cohen /* no vdev is in place ? */ 359*400e64dfSOhad Ben-Cohen if (!rvdev) { 360*400e64dfSOhad Ben-Cohen dev_err(dev, "vring requested without a virtio dev entry\n"); 361*400e64dfSOhad Ben-Cohen return -EINVAL; 362*400e64dfSOhad Ben-Cohen } 363*400e64dfSOhad Ben-Cohen 364*400e64dfSOhad Ben-Cohen /* the firmware must provide the expected queue size */ 365*400e64dfSOhad Ben-Cohen if (!rsc->len) { 366*400e64dfSOhad Ben-Cohen dev_err(dev, "missing expected queue size\n"); 367*400e64dfSOhad Ben-Cohen return -EINVAL; 368*400e64dfSOhad Ben-Cohen } 369*400e64dfSOhad Ben-Cohen 370*400e64dfSOhad Ben-Cohen /* we currently support two vrings per rproc (for rx and tx) */ 371*400e64dfSOhad Ben-Cohen if (id >= ARRAY_SIZE(rvdev->vring)) { 372*400e64dfSOhad Ben-Cohen dev_err(dev, "%s: invalid vring id %d\n", rsc->name, id); 373*400e64dfSOhad Ben-Cohen return -EINVAL; 374*400e64dfSOhad Ben-Cohen } 375*400e64dfSOhad Ben-Cohen 376*400e64dfSOhad Ben-Cohen /* have we already allocated this vring id ? */ 377*400e64dfSOhad Ben-Cohen if (rvdev->vring[id].len) { 378*400e64dfSOhad Ben-Cohen dev_err(dev, "%s: duplicated id %d\n", rsc->name, id); 379*400e64dfSOhad Ben-Cohen return -EINVAL; 380*400e64dfSOhad Ben-Cohen } 381*400e64dfSOhad Ben-Cohen 382*400e64dfSOhad Ben-Cohen /* actual size of vring (in bytes) */ 383*400e64dfSOhad Ben-Cohen size = PAGE_ALIGN(vring_size(rsc->len, AMP_VRING_ALIGN)); 384*400e64dfSOhad Ben-Cohen 385*400e64dfSOhad Ben-Cohen /* 386*400e64dfSOhad Ben-Cohen * Allocate non-cacheable memory for the vring. In the future 387*400e64dfSOhad Ben-Cohen * this call will also configure the IOMMU for us 388*400e64dfSOhad Ben-Cohen */ 389*400e64dfSOhad Ben-Cohen va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL); 390*400e64dfSOhad Ben-Cohen if (!va) { 391*400e64dfSOhad Ben-Cohen dev_err(dev, "dma_alloc_coherent failed\n"); 392*400e64dfSOhad Ben-Cohen return -ENOMEM; 393*400e64dfSOhad Ben-Cohen } 394*400e64dfSOhad Ben-Cohen 395*400e64dfSOhad Ben-Cohen dev_dbg(dev, "vring%d: va %p dma %x qsz %d ring size %x\n", id, va, 396*400e64dfSOhad Ben-Cohen dma, rsc->len, size); 397*400e64dfSOhad Ben-Cohen 398*400e64dfSOhad Ben-Cohen rvdev->vring[id].len = rsc->len; 399*400e64dfSOhad Ben-Cohen rvdev->vring[id].va = va; 400*400e64dfSOhad Ben-Cohen rvdev->vring[id].dma = dma; 401*400e64dfSOhad Ben-Cohen 402*400e64dfSOhad Ben-Cohen return 0; 403*400e64dfSOhad Ben-Cohen } 404*400e64dfSOhad Ben-Cohen 405*400e64dfSOhad Ben-Cohen /** 406*400e64dfSOhad Ben-Cohen * rproc_handle_trace() - handle a shared trace buffer resource 407*400e64dfSOhad Ben-Cohen * @rproc: the remote processor 408*400e64dfSOhad Ben-Cohen * @rsc: the trace resource descriptor 409*400e64dfSOhad Ben-Cohen * 410*400e64dfSOhad Ben-Cohen * In case the remote processor dumps trace logs into memory, 411*400e64dfSOhad Ben-Cohen * export it via debugfs. 412*400e64dfSOhad Ben-Cohen * 413*400e64dfSOhad Ben-Cohen * Currently, the 'da' member of @rsc should contain the device address 414*400e64dfSOhad Ben-Cohen * where the remote processor is dumping the traces. Later we could also 415*400e64dfSOhad Ben-Cohen * support dynamically allocating this address using the generic 416*400e64dfSOhad Ben-Cohen * DMA API (but currently there isn't a use case for that). 417*400e64dfSOhad Ben-Cohen * 418*400e64dfSOhad Ben-Cohen * Returns 0 on success, or an appropriate error code otherwise 419*400e64dfSOhad Ben-Cohen */ 420*400e64dfSOhad Ben-Cohen static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc) 421*400e64dfSOhad Ben-Cohen { 422*400e64dfSOhad Ben-Cohen struct rproc_mem_entry *trace; 423*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 424*400e64dfSOhad Ben-Cohen void *ptr; 425*400e64dfSOhad Ben-Cohen char name[15]; 426*400e64dfSOhad Ben-Cohen 427*400e64dfSOhad Ben-Cohen /* what's the kernel address of this resource ? */ 428*400e64dfSOhad Ben-Cohen ptr = rproc_da_to_va(rproc, rsc->da, rsc->len); 429*400e64dfSOhad Ben-Cohen if (!ptr) { 430*400e64dfSOhad Ben-Cohen dev_err(dev, "erroneous trace resource entry\n"); 431*400e64dfSOhad Ben-Cohen return -EINVAL; 432*400e64dfSOhad Ben-Cohen } 433*400e64dfSOhad Ben-Cohen 434*400e64dfSOhad Ben-Cohen trace = kzalloc(sizeof(*trace), GFP_KERNEL); 435*400e64dfSOhad Ben-Cohen if (!trace) { 436*400e64dfSOhad Ben-Cohen dev_err(dev, "kzalloc trace failed\n"); 437*400e64dfSOhad Ben-Cohen return -ENOMEM; 438*400e64dfSOhad Ben-Cohen } 439*400e64dfSOhad Ben-Cohen 440*400e64dfSOhad Ben-Cohen /* set the trace buffer dma properties */ 441*400e64dfSOhad Ben-Cohen trace->len = rsc->len; 442*400e64dfSOhad Ben-Cohen trace->va = ptr; 443*400e64dfSOhad Ben-Cohen 444*400e64dfSOhad Ben-Cohen /* make sure snprintf always null terminates, even if truncating */ 445*400e64dfSOhad Ben-Cohen snprintf(name, sizeof(name), "trace%d", rproc->num_traces); 446*400e64dfSOhad Ben-Cohen 447*400e64dfSOhad Ben-Cohen /* create the debugfs entry */ 448*400e64dfSOhad Ben-Cohen trace->priv = rproc_create_trace_file(name, rproc, trace); 449*400e64dfSOhad Ben-Cohen if (!trace->priv) { 450*400e64dfSOhad Ben-Cohen trace->va = NULL; 451*400e64dfSOhad Ben-Cohen kfree(trace); 452*400e64dfSOhad Ben-Cohen return -EINVAL; 453*400e64dfSOhad Ben-Cohen } 454*400e64dfSOhad Ben-Cohen 455*400e64dfSOhad Ben-Cohen list_add_tail(&trace->node, &rproc->traces); 456*400e64dfSOhad Ben-Cohen 457*400e64dfSOhad Ben-Cohen rproc->num_traces++; 458*400e64dfSOhad Ben-Cohen 459*400e64dfSOhad Ben-Cohen dev_dbg(dev, "%s added: va %p, da 0x%llx, len 0x%x\n", name, ptr, 460*400e64dfSOhad Ben-Cohen rsc->da, rsc->len); 461*400e64dfSOhad Ben-Cohen 462*400e64dfSOhad Ben-Cohen return 0; 463*400e64dfSOhad Ben-Cohen } 464*400e64dfSOhad Ben-Cohen 465*400e64dfSOhad Ben-Cohen /** 466*400e64dfSOhad Ben-Cohen * rproc_handle_devmem() - handle devmem resource entry 467*400e64dfSOhad Ben-Cohen * @rproc: remote processor handle 468*400e64dfSOhad Ben-Cohen * @rsc: the devmem resource entry 469*400e64dfSOhad Ben-Cohen * 470*400e64dfSOhad Ben-Cohen * Remote processors commonly need to access certain on-chip peripherals. 471*400e64dfSOhad Ben-Cohen * 472*400e64dfSOhad Ben-Cohen * Some of these remote processors access memory via an iommu device, 473*400e64dfSOhad Ben-Cohen * and might require us to configure their iommu before they can access 474*400e64dfSOhad Ben-Cohen * the on-chip peripherals they need. 475*400e64dfSOhad Ben-Cohen * 476*400e64dfSOhad Ben-Cohen * This resource entry is a request to map such a peripheral device. 477*400e64dfSOhad Ben-Cohen * 478*400e64dfSOhad Ben-Cohen * These devmem entries will contain the physical address of the device in 479*400e64dfSOhad Ben-Cohen * the 'pa' member. If a specific device address is expected, then 'da' will 480*400e64dfSOhad Ben-Cohen * contain it (currently this is the only use case supported). 'len' will 481*400e64dfSOhad Ben-Cohen * contain the size of the physical region we need to map. 482*400e64dfSOhad Ben-Cohen * 483*400e64dfSOhad Ben-Cohen * Currently we just "trust" those devmem entries to contain valid physical 484*400e64dfSOhad Ben-Cohen * addresses, but this is going to change: we want the implementations to 485*400e64dfSOhad Ben-Cohen * tell us ranges of physical addresses the firmware is allowed to request, 486*400e64dfSOhad Ben-Cohen * and not allow firmwares to request access to physical addresses that 487*400e64dfSOhad Ben-Cohen * are outside those ranges. 488*400e64dfSOhad Ben-Cohen */ 489*400e64dfSOhad Ben-Cohen static int rproc_handle_devmem(struct rproc *rproc, struct fw_resource *rsc) 490*400e64dfSOhad Ben-Cohen { 491*400e64dfSOhad Ben-Cohen struct rproc_mem_entry *mapping; 492*400e64dfSOhad Ben-Cohen int ret; 493*400e64dfSOhad Ben-Cohen 494*400e64dfSOhad Ben-Cohen /* no point in handling this resource without a valid iommu domain */ 495*400e64dfSOhad Ben-Cohen if (!rproc->domain) 496*400e64dfSOhad Ben-Cohen return -EINVAL; 497*400e64dfSOhad Ben-Cohen 498*400e64dfSOhad Ben-Cohen mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); 499*400e64dfSOhad Ben-Cohen if (!mapping) { 500*400e64dfSOhad Ben-Cohen dev_err(rproc->dev, "kzalloc mapping failed\n"); 501*400e64dfSOhad Ben-Cohen return -ENOMEM; 502*400e64dfSOhad Ben-Cohen } 503*400e64dfSOhad Ben-Cohen 504*400e64dfSOhad Ben-Cohen ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags); 505*400e64dfSOhad Ben-Cohen if (ret) { 506*400e64dfSOhad Ben-Cohen dev_err(rproc->dev, "failed to map devmem: %d\n", ret); 507*400e64dfSOhad Ben-Cohen goto out; 508*400e64dfSOhad Ben-Cohen } 509*400e64dfSOhad Ben-Cohen 510*400e64dfSOhad Ben-Cohen /* 511*400e64dfSOhad Ben-Cohen * We'll need this info later when we'll want to unmap everything 512*400e64dfSOhad Ben-Cohen * (e.g. on shutdown). 513*400e64dfSOhad Ben-Cohen * 514*400e64dfSOhad Ben-Cohen * We can't trust the remote processor not to change the resource 515*400e64dfSOhad Ben-Cohen * table, so we must maintain this info independently. 516*400e64dfSOhad Ben-Cohen */ 517*400e64dfSOhad Ben-Cohen mapping->da = rsc->da; 518*400e64dfSOhad Ben-Cohen mapping->len = rsc->len; 519*400e64dfSOhad Ben-Cohen list_add_tail(&mapping->node, &rproc->mappings); 520*400e64dfSOhad Ben-Cohen 521*400e64dfSOhad Ben-Cohen dev_dbg(rproc->dev, "mapped devmem pa 0x%llx, da 0x%llx, len 0x%x\n", 522*400e64dfSOhad Ben-Cohen rsc->pa, rsc->da, rsc->len); 523*400e64dfSOhad Ben-Cohen 524*400e64dfSOhad Ben-Cohen return 0; 525*400e64dfSOhad Ben-Cohen 526*400e64dfSOhad Ben-Cohen out: 527*400e64dfSOhad Ben-Cohen kfree(mapping); 528*400e64dfSOhad Ben-Cohen return ret; 529*400e64dfSOhad Ben-Cohen } 530*400e64dfSOhad Ben-Cohen 531*400e64dfSOhad Ben-Cohen /** 532*400e64dfSOhad Ben-Cohen * rproc_handle_carveout() - handle phys contig memory allocation requests 533*400e64dfSOhad Ben-Cohen * @rproc: rproc handle 534*400e64dfSOhad Ben-Cohen * @rsc: the resource entry 535*400e64dfSOhad Ben-Cohen * 536*400e64dfSOhad Ben-Cohen * This function will handle firmware requests for allocation of physically 537*400e64dfSOhad Ben-Cohen * contiguous memory regions. 538*400e64dfSOhad Ben-Cohen * 539*400e64dfSOhad Ben-Cohen * These request entries should come first in the firmware's resource table, 540*400e64dfSOhad Ben-Cohen * as other firmware entries might request placing other data objects inside 541*400e64dfSOhad Ben-Cohen * these memory regions (e.g. data/code segments, trace resource entries, ...). 542*400e64dfSOhad Ben-Cohen * 543*400e64dfSOhad Ben-Cohen * Allocating memory this way helps utilizing the reserved physical memory 544*400e64dfSOhad Ben-Cohen * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries 545*400e64dfSOhad Ben-Cohen * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB 546*400e64dfSOhad Ben-Cohen * pressure is important; it may have a substantial impact on performance. 547*400e64dfSOhad Ben-Cohen */ 548*400e64dfSOhad Ben-Cohen static int rproc_handle_carveout(struct rproc *rproc, struct fw_resource *rsc) 549*400e64dfSOhad Ben-Cohen { 550*400e64dfSOhad Ben-Cohen struct rproc_mem_entry *carveout, *mapping; 551*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 552*400e64dfSOhad Ben-Cohen dma_addr_t dma; 553*400e64dfSOhad Ben-Cohen void *va; 554*400e64dfSOhad Ben-Cohen int ret; 555*400e64dfSOhad Ben-Cohen 556*400e64dfSOhad Ben-Cohen mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); 557*400e64dfSOhad Ben-Cohen if (!mapping) { 558*400e64dfSOhad Ben-Cohen dev_err(dev, "kzalloc mapping failed\n"); 559*400e64dfSOhad Ben-Cohen return -ENOMEM; 560*400e64dfSOhad Ben-Cohen } 561*400e64dfSOhad Ben-Cohen 562*400e64dfSOhad Ben-Cohen carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); 563*400e64dfSOhad Ben-Cohen if (!carveout) { 564*400e64dfSOhad Ben-Cohen dev_err(dev, "kzalloc carveout failed\n"); 565*400e64dfSOhad Ben-Cohen ret = -ENOMEM; 566*400e64dfSOhad Ben-Cohen goto free_mapping; 567*400e64dfSOhad Ben-Cohen } 568*400e64dfSOhad Ben-Cohen 569*400e64dfSOhad Ben-Cohen va = dma_alloc_coherent(dev, rsc->len, &dma, GFP_KERNEL); 570*400e64dfSOhad Ben-Cohen if (!va) { 571*400e64dfSOhad Ben-Cohen dev_err(dev, "failed to dma alloc carveout: %d\n", rsc->len); 572*400e64dfSOhad Ben-Cohen ret = -ENOMEM; 573*400e64dfSOhad Ben-Cohen goto free_carv; 574*400e64dfSOhad Ben-Cohen } 575*400e64dfSOhad Ben-Cohen 576*400e64dfSOhad Ben-Cohen dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len); 577*400e64dfSOhad Ben-Cohen 578*400e64dfSOhad Ben-Cohen /* 579*400e64dfSOhad Ben-Cohen * Ok, this is non-standard. 580*400e64dfSOhad Ben-Cohen * 581*400e64dfSOhad Ben-Cohen * Sometimes we can't rely on the generic iommu-based DMA API 582*400e64dfSOhad Ben-Cohen * to dynamically allocate the device address and then set the IOMMU 583*400e64dfSOhad Ben-Cohen * tables accordingly, because some remote processors might 584*400e64dfSOhad Ben-Cohen * _require_ us to use hard coded device addresses that their 585*400e64dfSOhad Ben-Cohen * firmware was compiled with. 586*400e64dfSOhad Ben-Cohen * 587*400e64dfSOhad Ben-Cohen * In this case, we must use the IOMMU API directly and map 588*400e64dfSOhad Ben-Cohen * the memory to the device address as expected by the remote 589*400e64dfSOhad Ben-Cohen * processor. 590*400e64dfSOhad Ben-Cohen * 591*400e64dfSOhad Ben-Cohen * Obviously such remote processor devices should not be configured 592*400e64dfSOhad Ben-Cohen * to use the iommu-based DMA API: we expect 'dma' to contain the 593*400e64dfSOhad Ben-Cohen * physical address in this case. 594*400e64dfSOhad Ben-Cohen */ 595*400e64dfSOhad Ben-Cohen if (rproc->domain) { 596*400e64dfSOhad Ben-Cohen ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, 597*400e64dfSOhad Ben-Cohen rsc->flags); 598*400e64dfSOhad Ben-Cohen if (ret) { 599*400e64dfSOhad Ben-Cohen dev_err(dev, "iommu_map failed: %d\n", ret); 600*400e64dfSOhad Ben-Cohen goto dma_free; 601*400e64dfSOhad Ben-Cohen } 602*400e64dfSOhad Ben-Cohen 603*400e64dfSOhad Ben-Cohen /* 604*400e64dfSOhad Ben-Cohen * We'll need this info later when we'll want to unmap 605*400e64dfSOhad Ben-Cohen * everything (e.g. on shutdown). 606*400e64dfSOhad Ben-Cohen * 607*400e64dfSOhad Ben-Cohen * We can't trust the remote processor not to change the 608*400e64dfSOhad Ben-Cohen * resource table, so we must maintain this info independently. 609*400e64dfSOhad Ben-Cohen */ 610*400e64dfSOhad Ben-Cohen mapping->da = rsc->da; 611*400e64dfSOhad Ben-Cohen mapping->len = rsc->len; 612*400e64dfSOhad Ben-Cohen list_add_tail(&mapping->node, &rproc->mappings); 613*400e64dfSOhad Ben-Cohen 614*400e64dfSOhad Ben-Cohen dev_dbg(dev, "carveout mapped 0x%llx to 0x%x\n", rsc->da, dma); 615*400e64dfSOhad Ben-Cohen 616*400e64dfSOhad Ben-Cohen /* 617*400e64dfSOhad Ben-Cohen * Some remote processors might need to know the pa 618*400e64dfSOhad Ben-Cohen * even though they are behind an IOMMU. E.g., OMAP4's 619*400e64dfSOhad Ben-Cohen * remote M3 processor needs this so it can control 620*400e64dfSOhad Ben-Cohen * on-chip hardware accelerators that are not behind 621*400e64dfSOhad Ben-Cohen * the IOMMU, and therefor must know the pa. 622*400e64dfSOhad Ben-Cohen * 623*400e64dfSOhad Ben-Cohen * Generally we don't want to expose physical addresses 624*400e64dfSOhad Ben-Cohen * if we don't have to (remote processors are generally 625*400e64dfSOhad Ben-Cohen * _not_ trusted), so we might want to do this only for 626*400e64dfSOhad Ben-Cohen * remote processor that _must_ have this (e.g. OMAP4's 627*400e64dfSOhad Ben-Cohen * dual M3 subsystem). 628*400e64dfSOhad Ben-Cohen */ 629*400e64dfSOhad Ben-Cohen rsc->pa = dma; 630*400e64dfSOhad Ben-Cohen } 631*400e64dfSOhad Ben-Cohen 632*400e64dfSOhad Ben-Cohen carveout->va = va; 633*400e64dfSOhad Ben-Cohen carveout->len = rsc->len; 634*400e64dfSOhad Ben-Cohen carveout->dma = dma; 635*400e64dfSOhad Ben-Cohen carveout->da = rsc->da; 636*400e64dfSOhad Ben-Cohen 637*400e64dfSOhad Ben-Cohen list_add_tail(&carveout->node, &rproc->carveouts); 638*400e64dfSOhad Ben-Cohen 639*400e64dfSOhad Ben-Cohen return 0; 640*400e64dfSOhad Ben-Cohen 641*400e64dfSOhad Ben-Cohen dma_free: 642*400e64dfSOhad Ben-Cohen dma_free_coherent(dev, rsc->len, va, dma); 643*400e64dfSOhad Ben-Cohen free_carv: 644*400e64dfSOhad Ben-Cohen kfree(carveout); 645*400e64dfSOhad Ben-Cohen free_mapping: 646*400e64dfSOhad Ben-Cohen kfree(mapping); 647*400e64dfSOhad Ben-Cohen return ret; 648*400e64dfSOhad Ben-Cohen } 649*400e64dfSOhad Ben-Cohen 650*400e64dfSOhad Ben-Cohen /* handle firmware resource entries before booting the remote processor */ 651*400e64dfSOhad Ben-Cohen static int 652*400e64dfSOhad Ben-Cohen rproc_handle_boot_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) 653*400e64dfSOhad Ben-Cohen { 654*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 655*400e64dfSOhad Ben-Cohen int ret = 0; 656*400e64dfSOhad Ben-Cohen 657*400e64dfSOhad Ben-Cohen while (len >= sizeof(*rsc)) { 658*400e64dfSOhad Ben-Cohen dev_dbg(dev, "rsc: type %d, da 0x%llx, pa 0x%llx, len 0x%x, " 659*400e64dfSOhad Ben-Cohen "id %d, name %s, flags %x\n", rsc->type, rsc->da, 660*400e64dfSOhad Ben-Cohen rsc->pa, rsc->len, rsc->id, rsc->name, rsc->flags); 661*400e64dfSOhad Ben-Cohen 662*400e64dfSOhad Ben-Cohen switch (rsc->type) { 663*400e64dfSOhad Ben-Cohen case RSC_CARVEOUT: 664*400e64dfSOhad Ben-Cohen ret = rproc_handle_carveout(rproc, rsc); 665*400e64dfSOhad Ben-Cohen break; 666*400e64dfSOhad Ben-Cohen case RSC_DEVMEM: 667*400e64dfSOhad Ben-Cohen ret = rproc_handle_devmem(rproc, rsc); 668*400e64dfSOhad Ben-Cohen break; 669*400e64dfSOhad Ben-Cohen case RSC_TRACE: 670*400e64dfSOhad Ben-Cohen ret = rproc_handle_trace(rproc, rsc); 671*400e64dfSOhad Ben-Cohen break; 672*400e64dfSOhad Ben-Cohen case RSC_VRING: 673*400e64dfSOhad Ben-Cohen ret = rproc_handle_vring(rproc, rsc); 674*400e64dfSOhad Ben-Cohen break; 675*400e64dfSOhad Ben-Cohen case RSC_VIRTIO_DEV: 676*400e64dfSOhad Ben-Cohen /* this one is handled early upon registration */ 677*400e64dfSOhad Ben-Cohen break; 678*400e64dfSOhad Ben-Cohen default: 679*400e64dfSOhad Ben-Cohen dev_warn(dev, "unsupported resource %d\n", rsc->type); 680*400e64dfSOhad Ben-Cohen break; 681*400e64dfSOhad Ben-Cohen } 682*400e64dfSOhad Ben-Cohen 683*400e64dfSOhad Ben-Cohen if (ret) 684*400e64dfSOhad Ben-Cohen break; 685*400e64dfSOhad Ben-Cohen 686*400e64dfSOhad Ben-Cohen rsc++; 687*400e64dfSOhad Ben-Cohen len -= sizeof(*rsc); 688*400e64dfSOhad Ben-Cohen } 689*400e64dfSOhad Ben-Cohen 690*400e64dfSOhad Ben-Cohen return ret; 691*400e64dfSOhad Ben-Cohen } 692*400e64dfSOhad Ben-Cohen 693*400e64dfSOhad Ben-Cohen /* handle firmware resource entries while registering the remote processor */ 694*400e64dfSOhad Ben-Cohen static int 695*400e64dfSOhad Ben-Cohen rproc_handle_virtio_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) 696*400e64dfSOhad Ben-Cohen { 697*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 698*400e64dfSOhad Ben-Cohen int ret = 0; 699*400e64dfSOhad Ben-Cohen 700*400e64dfSOhad Ben-Cohen for (; len >= sizeof(*rsc); rsc++, len -= sizeof(*rsc)) 701*400e64dfSOhad Ben-Cohen if (rsc->type == RSC_VIRTIO_DEV) { 702*400e64dfSOhad Ben-Cohen dev_dbg(dev, "found vdev %d/%s features %llx\n", 703*400e64dfSOhad Ben-Cohen rsc->flags, rsc->name, rsc->da); 704*400e64dfSOhad Ben-Cohen ret = rproc_handle_virtio_hdr(rproc, rsc); 705*400e64dfSOhad Ben-Cohen break; 706*400e64dfSOhad Ben-Cohen } 707*400e64dfSOhad Ben-Cohen 708*400e64dfSOhad Ben-Cohen return ret; 709*400e64dfSOhad Ben-Cohen } 710*400e64dfSOhad Ben-Cohen 711*400e64dfSOhad Ben-Cohen /** 712*400e64dfSOhad Ben-Cohen * rproc_handle_resources() - find and handle the resource table 713*400e64dfSOhad Ben-Cohen * @rproc: the rproc handle 714*400e64dfSOhad Ben-Cohen * @elf_data: the content of the ELF firmware image 715*400e64dfSOhad Ben-Cohen * @handler: function that should be used to handle the resource table 716*400e64dfSOhad Ben-Cohen * 717*400e64dfSOhad Ben-Cohen * This function finds the resource table inside the remote processor's 718*400e64dfSOhad Ben-Cohen * firmware, and invoke a user-supplied handler with it (we have two 719*400e64dfSOhad Ben-Cohen * possible handlers: one is invoked upon registration of @rproc, 720*400e64dfSOhad Ben-Cohen * in order to register the supported virito devices, and the other is 721*400e64dfSOhad Ben-Cohen * invoked when @rproc is actually booted). 722*400e64dfSOhad Ben-Cohen * 723*400e64dfSOhad Ben-Cohen * Currently this function fails if a resource table doesn't exist. 724*400e64dfSOhad Ben-Cohen * This restriction will be removed when we'll start supporting remote 725*400e64dfSOhad Ben-Cohen * processors that don't need a resource table. 726*400e64dfSOhad Ben-Cohen */ 727*400e64dfSOhad Ben-Cohen static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, 728*400e64dfSOhad Ben-Cohen rproc_handle_resources_t handler) 729*400e64dfSOhad Ben-Cohen 730*400e64dfSOhad Ben-Cohen { 731*400e64dfSOhad Ben-Cohen struct elf32_hdr *ehdr; 732*400e64dfSOhad Ben-Cohen struct elf32_shdr *shdr; 733*400e64dfSOhad Ben-Cohen const char *name_table; 734*400e64dfSOhad Ben-Cohen int i, ret = -EINVAL; 735*400e64dfSOhad Ben-Cohen 736*400e64dfSOhad Ben-Cohen ehdr = (struct elf32_hdr *)elf_data; 737*400e64dfSOhad Ben-Cohen shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); 738*400e64dfSOhad Ben-Cohen name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset; 739*400e64dfSOhad Ben-Cohen 740*400e64dfSOhad Ben-Cohen /* look for the resource table and handle it */ 741*400e64dfSOhad Ben-Cohen for (i = 0; i < ehdr->e_shnum; i++, shdr++) { 742*400e64dfSOhad Ben-Cohen if (!strcmp(name_table + shdr->sh_name, ".resource_table")) { 743*400e64dfSOhad Ben-Cohen struct fw_resource *table = (struct fw_resource *) 744*400e64dfSOhad Ben-Cohen (elf_data + shdr->sh_offset); 745*400e64dfSOhad Ben-Cohen 746*400e64dfSOhad Ben-Cohen ret = handler(rproc, table, shdr->sh_size); 747*400e64dfSOhad Ben-Cohen 748*400e64dfSOhad Ben-Cohen break; 749*400e64dfSOhad Ben-Cohen } 750*400e64dfSOhad Ben-Cohen } 751*400e64dfSOhad Ben-Cohen 752*400e64dfSOhad Ben-Cohen return ret; 753*400e64dfSOhad Ben-Cohen } 754*400e64dfSOhad Ben-Cohen 755*400e64dfSOhad Ben-Cohen /** 756*400e64dfSOhad Ben-Cohen * rproc_resource_cleanup() - clean up and free all acquired resources 757*400e64dfSOhad Ben-Cohen * @rproc: rproc handle 758*400e64dfSOhad Ben-Cohen * 759*400e64dfSOhad Ben-Cohen * This function will free all resources acquired for @rproc, and it 760*400e64dfSOhad Ben-Cohen * is called when @rproc shuts down, or just failed booting. 761*400e64dfSOhad Ben-Cohen */ 762*400e64dfSOhad Ben-Cohen static void rproc_resource_cleanup(struct rproc *rproc) 763*400e64dfSOhad Ben-Cohen { 764*400e64dfSOhad Ben-Cohen struct rproc_mem_entry *entry, *tmp; 765*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 766*400e64dfSOhad Ben-Cohen struct rproc_vdev *rvdev = rproc->rvdev; 767*400e64dfSOhad Ben-Cohen int i; 768*400e64dfSOhad Ben-Cohen 769*400e64dfSOhad Ben-Cohen /* clean up debugfs trace entries */ 770*400e64dfSOhad Ben-Cohen list_for_each_entry_safe(entry, tmp, &rproc->traces, node) { 771*400e64dfSOhad Ben-Cohen rproc_remove_trace_file(entry->priv); 772*400e64dfSOhad Ben-Cohen rproc->num_traces--; 773*400e64dfSOhad Ben-Cohen list_del(&entry->node); 774*400e64dfSOhad Ben-Cohen kfree(entry); 775*400e64dfSOhad Ben-Cohen } 776*400e64dfSOhad Ben-Cohen 777*400e64dfSOhad Ben-Cohen /* free the coherent memory allocated for the vrings */ 778*400e64dfSOhad Ben-Cohen for (i = 0; rvdev && i < ARRAY_SIZE(rvdev->vring); i++) { 779*400e64dfSOhad Ben-Cohen int qsz = rvdev->vring[i].len; 780*400e64dfSOhad Ben-Cohen void *va = rvdev->vring[i].va; 781*400e64dfSOhad Ben-Cohen int dma = rvdev->vring[i].dma; 782*400e64dfSOhad Ben-Cohen 783*400e64dfSOhad Ben-Cohen /* virtqueue size is expressed in number of buffers supported */ 784*400e64dfSOhad Ben-Cohen if (qsz) { 785*400e64dfSOhad Ben-Cohen /* how many bytes does this vring really occupy ? */ 786*400e64dfSOhad Ben-Cohen int size = PAGE_ALIGN(vring_size(qsz, AMP_VRING_ALIGN)); 787*400e64dfSOhad Ben-Cohen 788*400e64dfSOhad Ben-Cohen dma_free_coherent(rproc->dev, size, va, dma); 789*400e64dfSOhad Ben-Cohen 790*400e64dfSOhad Ben-Cohen rvdev->vring[i].len = 0; 791*400e64dfSOhad Ben-Cohen } 792*400e64dfSOhad Ben-Cohen } 793*400e64dfSOhad Ben-Cohen 794*400e64dfSOhad Ben-Cohen /* clean up carveout allocations */ 795*400e64dfSOhad Ben-Cohen list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { 796*400e64dfSOhad Ben-Cohen dma_free_coherent(dev, entry->len, entry->va, entry->dma); 797*400e64dfSOhad Ben-Cohen list_del(&entry->node); 798*400e64dfSOhad Ben-Cohen kfree(entry); 799*400e64dfSOhad Ben-Cohen } 800*400e64dfSOhad Ben-Cohen 801*400e64dfSOhad Ben-Cohen /* clean up iommu mapping entries */ 802*400e64dfSOhad Ben-Cohen list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) { 803*400e64dfSOhad Ben-Cohen size_t unmapped; 804*400e64dfSOhad Ben-Cohen 805*400e64dfSOhad Ben-Cohen unmapped = iommu_unmap(rproc->domain, entry->da, entry->len); 806*400e64dfSOhad Ben-Cohen if (unmapped != entry->len) { 807*400e64dfSOhad Ben-Cohen /* nothing much to do besides complaining */ 808*400e64dfSOhad Ben-Cohen dev_err(dev, "failed to unmap %u/%u\n", entry->len, 809*400e64dfSOhad Ben-Cohen unmapped); 810*400e64dfSOhad Ben-Cohen } 811*400e64dfSOhad Ben-Cohen 812*400e64dfSOhad Ben-Cohen list_del(&entry->node); 813*400e64dfSOhad Ben-Cohen kfree(entry); 814*400e64dfSOhad Ben-Cohen } 815*400e64dfSOhad Ben-Cohen } 816*400e64dfSOhad Ben-Cohen 817*400e64dfSOhad Ben-Cohen /* make sure this fw image is sane */ 818*400e64dfSOhad Ben-Cohen static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) 819*400e64dfSOhad Ben-Cohen { 820*400e64dfSOhad Ben-Cohen const char *name = rproc->firmware; 821*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 822*400e64dfSOhad Ben-Cohen struct elf32_hdr *ehdr; 823*400e64dfSOhad Ben-Cohen 824*400e64dfSOhad Ben-Cohen if (!fw) { 825*400e64dfSOhad Ben-Cohen dev_err(dev, "failed to load %s\n", name); 826*400e64dfSOhad Ben-Cohen return -EINVAL; 827*400e64dfSOhad Ben-Cohen } 828*400e64dfSOhad Ben-Cohen 829*400e64dfSOhad Ben-Cohen if (fw->size < sizeof(struct elf32_hdr)) { 830*400e64dfSOhad Ben-Cohen dev_err(dev, "Image is too small\n"); 831*400e64dfSOhad Ben-Cohen return -EINVAL; 832*400e64dfSOhad Ben-Cohen } 833*400e64dfSOhad Ben-Cohen 834*400e64dfSOhad Ben-Cohen ehdr = (struct elf32_hdr *)fw->data; 835*400e64dfSOhad Ben-Cohen 836*400e64dfSOhad Ben-Cohen if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { 837*400e64dfSOhad Ben-Cohen dev_err(dev, "Image is corrupted (bad magic)\n"); 838*400e64dfSOhad Ben-Cohen return -EINVAL; 839*400e64dfSOhad Ben-Cohen } 840*400e64dfSOhad Ben-Cohen 841*400e64dfSOhad Ben-Cohen if (ehdr->e_phnum == 0) { 842*400e64dfSOhad Ben-Cohen dev_err(dev, "No loadable segments\n"); 843*400e64dfSOhad Ben-Cohen return -EINVAL; 844*400e64dfSOhad Ben-Cohen } 845*400e64dfSOhad Ben-Cohen 846*400e64dfSOhad Ben-Cohen if (ehdr->e_phoff > fw->size) { 847*400e64dfSOhad Ben-Cohen dev_err(dev, "Firmware size is too small\n"); 848*400e64dfSOhad Ben-Cohen return -EINVAL; 849*400e64dfSOhad Ben-Cohen } 850*400e64dfSOhad Ben-Cohen 851*400e64dfSOhad Ben-Cohen return 0; 852*400e64dfSOhad Ben-Cohen } 853*400e64dfSOhad Ben-Cohen 854*400e64dfSOhad Ben-Cohen /* 855*400e64dfSOhad Ben-Cohen * take a firmware and boot a remote processor with it. 856*400e64dfSOhad Ben-Cohen */ 857*400e64dfSOhad Ben-Cohen static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) 858*400e64dfSOhad Ben-Cohen { 859*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 860*400e64dfSOhad Ben-Cohen const char *name = rproc->firmware; 861*400e64dfSOhad Ben-Cohen struct elf32_hdr *ehdr; 862*400e64dfSOhad Ben-Cohen int ret; 863*400e64dfSOhad Ben-Cohen 864*400e64dfSOhad Ben-Cohen ret = rproc_fw_sanity_check(rproc, fw); 865*400e64dfSOhad Ben-Cohen if (ret) 866*400e64dfSOhad Ben-Cohen return ret; 867*400e64dfSOhad Ben-Cohen 868*400e64dfSOhad Ben-Cohen ehdr = (struct elf32_hdr *)fw->data; 869*400e64dfSOhad Ben-Cohen 870*400e64dfSOhad Ben-Cohen dev_info(dev, "Booting fw image %s, size %d\n", name, fw->size); 871*400e64dfSOhad Ben-Cohen 872*400e64dfSOhad Ben-Cohen /* 873*400e64dfSOhad Ben-Cohen * if enabling an IOMMU isn't relevant for this rproc, this is 874*400e64dfSOhad Ben-Cohen * just a nop 875*400e64dfSOhad Ben-Cohen */ 876*400e64dfSOhad Ben-Cohen ret = rproc_enable_iommu(rproc); 877*400e64dfSOhad Ben-Cohen if (ret) { 878*400e64dfSOhad Ben-Cohen dev_err(dev, "can't enable iommu: %d\n", ret); 879*400e64dfSOhad Ben-Cohen return ret; 880*400e64dfSOhad Ben-Cohen } 881*400e64dfSOhad Ben-Cohen 882*400e64dfSOhad Ben-Cohen /* 883*400e64dfSOhad Ben-Cohen * The ELF entry point is the rproc's boot addr (though this is not 884*400e64dfSOhad Ben-Cohen * a configurable property of all remote processors: some will always 885*400e64dfSOhad Ben-Cohen * boot at a specific hardcoded address). 886*400e64dfSOhad Ben-Cohen */ 887*400e64dfSOhad Ben-Cohen rproc->bootaddr = ehdr->e_entry; 888*400e64dfSOhad Ben-Cohen 889*400e64dfSOhad Ben-Cohen /* handle fw resources which are required to boot rproc */ 890*400e64dfSOhad Ben-Cohen ret = rproc_handle_resources(rproc, fw->data, rproc_handle_boot_rsc); 891*400e64dfSOhad Ben-Cohen if (ret) { 892*400e64dfSOhad Ben-Cohen dev_err(dev, "Failed to process resources: %d\n", ret); 893*400e64dfSOhad Ben-Cohen goto clean_up; 894*400e64dfSOhad Ben-Cohen } 895*400e64dfSOhad Ben-Cohen 896*400e64dfSOhad Ben-Cohen /* load the ELF segments to memory */ 897*400e64dfSOhad Ben-Cohen ret = rproc_load_segments(rproc, fw->data); 898*400e64dfSOhad Ben-Cohen if (ret) { 899*400e64dfSOhad Ben-Cohen dev_err(dev, "Failed to load program segments: %d\n", ret); 900*400e64dfSOhad Ben-Cohen goto clean_up; 901*400e64dfSOhad Ben-Cohen } 902*400e64dfSOhad Ben-Cohen 903*400e64dfSOhad Ben-Cohen /* power up the remote processor */ 904*400e64dfSOhad Ben-Cohen ret = rproc->ops->start(rproc); 905*400e64dfSOhad Ben-Cohen if (ret) { 906*400e64dfSOhad Ben-Cohen dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); 907*400e64dfSOhad Ben-Cohen goto clean_up; 908*400e64dfSOhad Ben-Cohen } 909*400e64dfSOhad Ben-Cohen 910*400e64dfSOhad Ben-Cohen rproc->state = RPROC_RUNNING; 911*400e64dfSOhad Ben-Cohen 912*400e64dfSOhad Ben-Cohen dev_info(dev, "remote processor %s is now up\n", rproc->name); 913*400e64dfSOhad Ben-Cohen 914*400e64dfSOhad Ben-Cohen return 0; 915*400e64dfSOhad Ben-Cohen 916*400e64dfSOhad Ben-Cohen clean_up: 917*400e64dfSOhad Ben-Cohen rproc_resource_cleanup(rproc); 918*400e64dfSOhad Ben-Cohen rproc_disable_iommu(rproc); 919*400e64dfSOhad Ben-Cohen return ret; 920*400e64dfSOhad Ben-Cohen } 921*400e64dfSOhad Ben-Cohen 922*400e64dfSOhad Ben-Cohen /* 923*400e64dfSOhad Ben-Cohen * take a firmware and look for virtio devices to register. 924*400e64dfSOhad Ben-Cohen * 925*400e64dfSOhad Ben-Cohen * Note: this function is called asynchronously upon registration of the 926*400e64dfSOhad Ben-Cohen * remote processor (so we must wait until it completes before we try 927*400e64dfSOhad Ben-Cohen * to unregister the device. one other option is just to use kref here, 928*400e64dfSOhad Ben-Cohen * that might be cleaner). 929*400e64dfSOhad Ben-Cohen */ 930*400e64dfSOhad Ben-Cohen static void rproc_fw_config_virtio(const struct firmware *fw, void *context) 931*400e64dfSOhad Ben-Cohen { 932*400e64dfSOhad Ben-Cohen struct rproc *rproc = context; 933*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 934*400e64dfSOhad Ben-Cohen int ret; 935*400e64dfSOhad Ben-Cohen 936*400e64dfSOhad Ben-Cohen if (rproc_fw_sanity_check(rproc, fw) < 0) 937*400e64dfSOhad Ben-Cohen goto out; 938*400e64dfSOhad Ben-Cohen 939*400e64dfSOhad Ben-Cohen /* does the fw supports any virtio devices ? */ 940*400e64dfSOhad Ben-Cohen ret = rproc_handle_resources(rproc, fw->data, rproc_handle_virtio_rsc); 941*400e64dfSOhad Ben-Cohen if (ret) { 942*400e64dfSOhad Ben-Cohen dev_info(dev, "No fw virtio device was found\n"); 943*400e64dfSOhad Ben-Cohen goto out; 944*400e64dfSOhad Ben-Cohen } 945*400e64dfSOhad Ben-Cohen 946*400e64dfSOhad Ben-Cohen /* add the virtio device (currently only rpmsg vdevs are supported) */ 947*400e64dfSOhad Ben-Cohen ret = rproc_add_rpmsg_vdev(rproc); 948*400e64dfSOhad Ben-Cohen if (ret) 949*400e64dfSOhad Ben-Cohen goto out; 950*400e64dfSOhad Ben-Cohen 951*400e64dfSOhad Ben-Cohen out: 952*400e64dfSOhad Ben-Cohen if (fw) 953*400e64dfSOhad Ben-Cohen release_firmware(fw); 954*400e64dfSOhad Ben-Cohen /* allow rproc_unregister() contexts, if any, to proceed */ 955*400e64dfSOhad Ben-Cohen complete_all(&rproc->firmware_loading_complete); 956*400e64dfSOhad Ben-Cohen } 957*400e64dfSOhad Ben-Cohen 958*400e64dfSOhad Ben-Cohen /** 959*400e64dfSOhad Ben-Cohen * rproc_boot() - boot a remote processor 960*400e64dfSOhad Ben-Cohen * @rproc: handle of a remote processor 961*400e64dfSOhad Ben-Cohen * 962*400e64dfSOhad Ben-Cohen * Boot a remote processor (i.e. load its firmware, power it on, ...). 963*400e64dfSOhad Ben-Cohen * 964*400e64dfSOhad Ben-Cohen * If the remote processor is already powered on, this function immediately 965*400e64dfSOhad Ben-Cohen * returns (successfully). 966*400e64dfSOhad Ben-Cohen * 967*400e64dfSOhad Ben-Cohen * Returns 0 on success, and an appropriate error value otherwise. 968*400e64dfSOhad Ben-Cohen */ 969*400e64dfSOhad Ben-Cohen int rproc_boot(struct rproc *rproc) 970*400e64dfSOhad Ben-Cohen { 971*400e64dfSOhad Ben-Cohen const struct firmware *firmware_p; 972*400e64dfSOhad Ben-Cohen struct device *dev; 973*400e64dfSOhad Ben-Cohen int ret; 974*400e64dfSOhad Ben-Cohen 975*400e64dfSOhad Ben-Cohen if (!rproc) { 976*400e64dfSOhad Ben-Cohen pr_err("invalid rproc handle\n"); 977*400e64dfSOhad Ben-Cohen return -EINVAL; 978*400e64dfSOhad Ben-Cohen } 979*400e64dfSOhad Ben-Cohen 980*400e64dfSOhad Ben-Cohen dev = rproc->dev; 981*400e64dfSOhad Ben-Cohen 982*400e64dfSOhad Ben-Cohen ret = mutex_lock_interruptible(&rproc->lock); 983*400e64dfSOhad Ben-Cohen if (ret) { 984*400e64dfSOhad Ben-Cohen dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); 985*400e64dfSOhad Ben-Cohen return ret; 986*400e64dfSOhad Ben-Cohen } 987*400e64dfSOhad Ben-Cohen 988*400e64dfSOhad Ben-Cohen /* loading a firmware is required */ 989*400e64dfSOhad Ben-Cohen if (!rproc->firmware) { 990*400e64dfSOhad Ben-Cohen dev_err(dev, "%s: no firmware to load\n", __func__); 991*400e64dfSOhad Ben-Cohen ret = -EINVAL; 992*400e64dfSOhad Ben-Cohen goto unlock_mutex; 993*400e64dfSOhad Ben-Cohen } 994*400e64dfSOhad Ben-Cohen 995*400e64dfSOhad Ben-Cohen /* prevent underlying implementation from being removed */ 996*400e64dfSOhad Ben-Cohen if (!try_module_get(dev->driver->owner)) { 997*400e64dfSOhad Ben-Cohen dev_err(dev, "%s: can't get owner\n", __func__); 998*400e64dfSOhad Ben-Cohen ret = -EINVAL; 999*400e64dfSOhad Ben-Cohen goto unlock_mutex; 1000*400e64dfSOhad Ben-Cohen } 1001*400e64dfSOhad Ben-Cohen 1002*400e64dfSOhad Ben-Cohen /* skip the boot process if rproc is already powered up */ 1003*400e64dfSOhad Ben-Cohen if (atomic_inc_return(&rproc->power) > 1) { 1004*400e64dfSOhad Ben-Cohen ret = 0; 1005*400e64dfSOhad Ben-Cohen goto unlock_mutex; 1006*400e64dfSOhad Ben-Cohen } 1007*400e64dfSOhad Ben-Cohen 1008*400e64dfSOhad Ben-Cohen dev_info(dev, "powering up %s\n", rproc->name); 1009*400e64dfSOhad Ben-Cohen 1010*400e64dfSOhad Ben-Cohen /* load firmware */ 1011*400e64dfSOhad Ben-Cohen ret = request_firmware(&firmware_p, rproc->firmware, dev); 1012*400e64dfSOhad Ben-Cohen if (ret < 0) { 1013*400e64dfSOhad Ben-Cohen dev_err(dev, "request_firmware failed: %d\n", ret); 1014*400e64dfSOhad Ben-Cohen goto downref_rproc; 1015*400e64dfSOhad Ben-Cohen } 1016*400e64dfSOhad Ben-Cohen 1017*400e64dfSOhad Ben-Cohen ret = rproc_fw_boot(rproc, firmware_p); 1018*400e64dfSOhad Ben-Cohen 1019*400e64dfSOhad Ben-Cohen release_firmware(firmware_p); 1020*400e64dfSOhad Ben-Cohen 1021*400e64dfSOhad Ben-Cohen downref_rproc: 1022*400e64dfSOhad Ben-Cohen if (ret) { 1023*400e64dfSOhad Ben-Cohen module_put(dev->driver->owner); 1024*400e64dfSOhad Ben-Cohen atomic_dec(&rproc->power); 1025*400e64dfSOhad Ben-Cohen } 1026*400e64dfSOhad Ben-Cohen unlock_mutex: 1027*400e64dfSOhad Ben-Cohen mutex_unlock(&rproc->lock); 1028*400e64dfSOhad Ben-Cohen return ret; 1029*400e64dfSOhad Ben-Cohen } 1030*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_boot); 1031*400e64dfSOhad Ben-Cohen 1032*400e64dfSOhad Ben-Cohen /** 1033*400e64dfSOhad Ben-Cohen * rproc_shutdown() - power off the remote processor 1034*400e64dfSOhad Ben-Cohen * @rproc: the remote processor 1035*400e64dfSOhad Ben-Cohen * 1036*400e64dfSOhad Ben-Cohen * Power off a remote processor (previously booted with rproc_boot()). 1037*400e64dfSOhad Ben-Cohen * 1038*400e64dfSOhad Ben-Cohen * In case @rproc is still being used by an additional user(s), then 1039*400e64dfSOhad Ben-Cohen * this function will just decrement the power refcount and exit, 1040*400e64dfSOhad Ben-Cohen * without really powering off the device. 1041*400e64dfSOhad Ben-Cohen * 1042*400e64dfSOhad Ben-Cohen * Every call to rproc_boot() must (eventually) be accompanied by a call 1043*400e64dfSOhad Ben-Cohen * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug. 1044*400e64dfSOhad Ben-Cohen * 1045*400e64dfSOhad Ben-Cohen * Notes: 1046*400e64dfSOhad Ben-Cohen * - we're not decrementing the rproc's refcount, only the power refcount. 1047*400e64dfSOhad Ben-Cohen * which means that the @rproc handle stays valid even after rproc_shutdown() 1048*400e64dfSOhad Ben-Cohen * returns, and users can still use it with a subsequent rproc_boot(), if 1049*400e64dfSOhad Ben-Cohen * needed. 1050*400e64dfSOhad Ben-Cohen * - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly 1051*400e64dfSOhad Ben-Cohen * because rproc_shutdown() _does not_ decrement the refcount of @rproc. 1052*400e64dfSOhad Ben-Cohen * To decrement the refcount of @rproc, use rproc_put() (but _only_ if 1053*400e64dfSOhad Ben-Cohen * you acquired @rproc using rproc_get_by_name()). 1054*400e64dfSOhad Ben-Cohen */ 1055*400e64dfSOhad Ben-Cohen void rproc_shutdown(struct rproc *rproc) 1056*400e64dfSOhad Ben-Cohen { 1057*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 1058*400e64dfSOhad Ben-Cohen int ret; 1059*400e64dfSOhad Ben-Cohen 1060*400e64dfSOhad Ben-Cohen ret = mutex_lock_interruptible(&rproc->lock); 1061*400e64dfSOhad Ben-Cohen if (ret) { 1062*400e64dfSOhad Ben-Cohen dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); 1063*400e64dfSOhad Ben-Cohen return; 1064*400e64dfSOhad Ben-Cohen } 1065*400e64dfSOhad Ben-Cohen 1066*400e64dfSOhad Ben-Cohen /* if the remote proc is still needed, bail out */ 1067*400e64dfSOhad Ben-Cohen if (!atomic_dec_and_test(&rproc->power)) 1068*400e64dfSOhad Ben-Cohen goto out; 1069*400e64dfSOhad Ben-Cohen 1070*400e64dfSOhad Ben-Cohen /* power off the remote processor */ 1071*400e64dfSOhad Ben-Cohen ret = rproc->ops->stop(rproc); 1072*400e64dfSOhad Ben-Cohen if (ret) { 1073*400e64dfSOhad Ben-Cohen atomic_inc(&rproc->power); 1074*400e64dfSOhad Ben-Cohen dev_err(dev, "can't stop rproc: %d\n", ret); 1075*400e64dfSOhad Ben-Cohen goto out; 1076*400e64dfSOhad Ben-Cohen } 1077*400e64dfSOhad Ben-Cohen 1078*400e64dfSOhad Ben-Cohen /* clean up all acquired resources */ 1079*400e64dfSOhad Ben-Cohen rproc_resource_cleanup(rproc); 1080*400e64dfSOhad Ben-Cohen 1081*400e64dfSOhad Ben-Cohen rproc_disable_iommu(rproc); 1082*400e64dfSOhad Ben-Cohen 1083*400e64dfSOhad Ben-Cohen rproc->state = RPROC_OFFLINE; 1084*400e64dfSOhad Ben-Cohen 1085*400e64dfSOhad Ben-Cohen dev_info(dev, "stopped remote processor %s\n", rproc->name); 1086*400e64dfSOhad Ben-Cohen 1087*400e64dfSOhad Ben-Cohen out: 1088*400e64dfSOhad Ben-Cohen mutex_unlock(&rproc->lock); 1089*400e64dfSOhad Ben-Cohen if (!ret) 1090*400e64dfSOhad Ben-Cohen module_put(dev->driver->owner); 1091*400e64dfSOhad Ben-Cohen } 1092*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_shutdown); 1093*400e64dfSOhad Ben-Cohen 1094*400e64dfSOhad Ben-Cohen /** 1095*400e64dfSOhad Ben-Cohen * rproc_release() - completely deletes the existence of a remote processor 1096*400e64dfSOhad Ben-Cohen * @kref: the rproc's kref 1097*400e64dfSOhad Ben-Cohen * 1098*400e64dfSOhad Ben-Cohen * This function should _never_ be called directly. 1099*400e64dfSOhad Ben-Cohen * 1100*400e64dfSOhad Ben-Cohen * The only reasonable location to use it is as an argument when kref_put'ing 1101*400e64dfSOhad Ben-Cohen * @rproc's refcount. 1102*400e64dfSOhad Ben-Cohen * 1103*400e64dfSOhad Ben-Cohen * This way it will be called when no one holds a valid pointer to this @rproc 1104*400e64dfSOhad Ben-Cohen * anymore (and obviously after it is removed from the rprocs klist). 1105*400e64dfSOhad Ben-Cohen * 1106*400e64dfSOhad Ben-Cohen * Note: this function is not static because rproc_vdev_release() needs it when 1107*400e64dfSOhad Ben-Cohen * it decrements @rproc's refcount. 1108*400e64dfSOhad Ben-Cohen */ 1109*400e64dfSOhad Ben-Cohen void rproc_release(struct kref *kref) 1110*400e64dfSOhad Ben-Cohen { 1111*400e64dfSOhad Ben-Cohen struct rproc *rproc = container_of(kref, struct rproc, refcount); 1112*400e64dfSOhad Ben-Cohen 1113*400e64dfSOhad Ben-Cohen dev_info(rproc->dev, "removing %s\n", rproc->name); 1114*400e64dfSOhad Ben-Cohen 1115*400e64dfSOhad Ben-Cohen rproc_delete_debug_dir(rproc); 1116*400e64dfSOhad Ben-Cohen 1117*400e64dfSOhad Ben-Cohen /* at this point no one holds a reference to rproc anymore */ 1118*400e64dfSOhad Ben-Cohen kfree(rproc); 1119*400e64dfSOhad Ben-Cohen } 1120*400e64dfSOhad Ben-Cohen 1121*400e64dfSOhad Ben-Cohen /* will be called when an rproc is added to the rprocs klist */ 1122*400e64dfSOhad Ben-Cohen static void klist_rproc_get(struct klist_node *n) 1123*400e64dfSOhad Ben-Cohen { 1124*400e64dfSOhad Ben-Cohen struct rproc *rproc = container_of(n, struct rproc, node); 1125*400e64dfSOhad Ben-Cohen 1126*400e64dfSOhad Ben-Cohen kref_get(&rproc->refcount); 1127*400e64dfSOhad Ben-Cohen } 1128*400e64dfSOhad Ben-Cohen 1129*400e64dfSOhad Ben-Cohen /* will be called when an rproc is removed from the rprocs klist */ 1130*400e64dfSOhad Ben-Cohen static void klist_rproc_put(struct klist_node *n) 1131*400e64dfSOhad Ben-Cohen { 1132*400e64dfSOhad Ben-Cohen struct rproc *rproc = container_of(n, struct rproc, node); 1133*400e64dfSOhad Ben-Cohen 1134*400e64dfSOhad Ben-Cohen kref_put(&rproc->refcount, rproc_release); 1135*400e64dfSOhad Ben-Cohen } 1136*400e64dfSOhad Ben-Cohen 1137*400e64dfSOhad Ben-Cohen static struct rproc *next_rproc(struct klist_iter *i) 1138*400e64dfSOhad Ben-Cohen { 1139*400e64dfSOhad Ben-Cohen struct klist_node *n; 1140*400e64dfSOhad Ben-Cohen 1141*400e64dfSOhad Ben-Cohen n = klist_next(i); 1142*400e64dfSOhad Ben-Cohen if (!n) 1143*400e64dfSOhad Ben-Cohen return NULL; 1144*400e64dfSOhad Ben-Cohen 1145*400e64dfSOhad Ben-Cohen return container_of(n, struct rproc, node); 1146*400e64dfSOhad Ben-Cohen } 1147*400e64dfSOhad Ben-Cohen 1148*400e64dfSOhad Ben-Cohen /** 1149*400e64dfSOhad Ben-Cohen * rproc_get_by_name() - find a remote processor by name and boot it 1150*400e64dfSOhad Ben-Cohen * @name: name of the remote processor 1151*400e64dfSOhad Ben-Cohen * 1152*400e64dfSOhad Ben-Cohen * Finds an rproc handle using the remote processor's name, and then 1153*400e64dfSOhad Ben-Cohen * boot it. If it's already powered on, then just immediately return 1154*400e64dfSOhad Ben-Cohen * (successfully). 1155*400e64dfSOhad Ben-Cohen * 1156*400e64dfSOhad Ben-Cohen * Returns the rproc handle on success, and NULL on failure. 1157*400e64dfSOhad Ben-Cohen * 1158*400e64dfSOhad Ben-Cohen * This function increments the remote processor's refcount, so always 1159*400e64dfSOhad Ben-Cohen * use rproc_put() to decrement it back once rproc isn't needed anymore. 1160*400e64dfSOhad Ben-Cohen * 1161*400e64dfSOhad Ben-Cohen * Note: currently this function (and its counterpart rproc_put()) are not 1162*400e64dfSOhad Ben-Cohen * used anymore by the rpmsg subsystem. We need to scrutinize the use cases 1163*400e64dfSOhad Ben-Cohen * that still need them, and see if we can migrate them to use the non 1164*400e64dfSOhad Ben-Cohen * name-based boot/shutdown interface. 1165*400e64dfSOhad Ben-Cohen */ 1166*400e64dfSOhad Ben-Cohen struct rproc *rproc_get_by_name(const char *name) 1167*400e64dfSOhad Ben-Cohen { 1168*400e64dfSOhad Ben-Cohen struct rproc *rproc; 1169*400e64dfSOhad Ben-Cohen struct klist_iter i; 1170*400e64dfSOhad Ben-Cohen int ret; 1171*400e64dfSOhad Ben-Cohen 1172*400e64dfSOhad Ben-Cohen /* find the remote processor, and upref its refcount */ 1173*400e64dfSOhad Ben-Cohen klist_iter_init(&rprocs, &i); 1174*400e64dfSOhad Ben-Cohen while ((rproc = next_rproc(&i)) != NULL) 1175*400e64dfSOhad Ben-Cohen if (!strcmp(rproc->name, name)) { 1176*400e64dfSOhad Ben-Cohen kref_get(&rproc->refcount); 1177*400e64dfSOhad Ben-Cohen break; 1178*400e64dfSOhad Ben-Cohen } 1179*400e64dfSOhad Ben-Cohen klist_iter_exit(&i); 1180*400e64dfSOhad Ben-Cohen 1181*400e64dfSOhad Ben-Cohen /* can't find this rproc ? */ 1182*400e64dfSOhad Ben-Cohen if (!rproc) { 1183*400e64dfSOhad Ben-Cohen pr_err("can't find remote processor %s\n", name); 1184*400e64dfSOhad Ben-Cohen return NULL; 1185*400e64dfSOhad Ben-Cohen } 1186*400e64dfSOhad Ben-Cohen 1187*400e64dfSOhad Ben-Cohen ret = rproc_boot(rproc); 1188*400e64dfSOhad Ben-Cohen if (ret < 0) { 1189*400e64dfSOhad Ben-Cohen kref_put(&rproc->refcount, rproc_release); 1190*400e64dfSOhad Ben-Cohen return NULL; 1191*400e64dfSOhad Ben-Cohen } 1192*400e64dfSOhad Ben-Cohen 1193*400e64dfSOhad Ben-Cohen return rproc; 1194*400e64dfSOhad Ben-Cohen } 1195*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_get_by_name); 1196*400e64dfSOhad Ben-Cohen 1197*400e64dfSOhad Ben-Cohen /** 1198*400e64dfSOhad Ben-Cohen * rproc_put() - decrement the refcount of a remote processor, and shut it down 1199*400e64dfSOhad Ben-Cohen * @rproc: the remote processor 1200*400e64dfSOhad Ben-Cohen * 1201*400e64dfSOhad Ben-Cohen * This function tries to shutdown @rproc, and it then decrements its 1202*400e64dfSOhad Ben-Cohen * refcount. 1203*400e64dfSOhad Ben-Cohen * 1204*400e64dfSOhad Ben-Cohen * After this function returns, @rproc may _not_ be used anymore, and its 1205*400e64dfSOhad Ben-Cohen * handle should be considered invalid. 1206*400e64dfSOhad Ben-Cohen * 1207*400e64dfSOhad Ben-Cohen * This function should be called _iff_ the @rproc handle was grabbed by 1208*400e64dfSOhad Ben-Cohen * calling rproc_get_by_name(). 1209*400e64dfSOhad Ben-Cohen */ 1210*400e64dfSOhad Ben-Cohen void rproc_put(struct rproc *rproc) 1211*400e64dfSOhad Ben-Cohen { 1212*400e64dfSOhad Ben-Cohen /* try to power off the remote processor */ 1213*400e64dfSOhad Ben-Cohen rproc_shutdown(rproc); 1214*400e64dfSOhad Ben-Cohen 1215*400e64dfSOhad Ben-Cohen /* downref rproc's refcount */ 1216*400e64dfSOhad Ben-Cohen kref_put(&rproc->refcount, rproc_release); 1217*400e64dfSOhad Ben-Cohen } 1218*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_put); 1219*400e64dfSOhad Ben-Cohen 1220*400e64dfSOhad Ben-Cohen /** 1221*400e64dfSOhad Ben-Cohen * rproc_register() - register a remote processor 1222*400e64dfSOhad Ben-Cohen * @rproc: the remote processor handle to register 1223*400e64dfSOhad Ben-Cohen * 1224*400e64dfSOhad Ben-Cohen * Registers @rproc with the remoteproc framework, after it has been 1225*400e64dfSOhad Ben-Cohen * allocated with rproc_alloc(). 1226*400e64dfSOhad Ben-Cohen * 1227*400e64dfSOhad Ben-Cohen * This is called by the platform-specific rproc implementation, whenever 1228*400e64dfSOhad Ben-Cohen * a new remote processor device is probed. 1229*400e64dfSOhad Ben-Cohen * 1230*400e64dfSOhad Ben-Cohen * Returns 0 on success and an appropriate error code otherwise. 1231*400e64dfSOhad Ben-Cohen * 1232*400e64dfSOhad Ben-Cohen * Note: this function initiates an asynchronous firmware loading 1233*400e64dfSOhad Ben-Cohen * context, which will look for virtio devices supported by the rproc's 1234*400e64dfSOhad Ben-Cohen * firmware. 1235*400e64dfSOhad Ben-Cohen * 1236*400e64dfSOhad Ben-Cohen * If found, those virtio devices will be created and added, so as a result 1237*400e64dfSOhad Ben-Cohen * of registering this remote processor, additional virtio drivers will be 1238*400e64dfSOhad Ben-Cohen * probed. 1239*400e64dfSOhad Ben-Cohen * 1240*400e64dfSOhad Ben-Cohen * Currently, though, we only support a single RPMSG virtio vdev per remote 1241*400e64dfSOhad Ben-Cohen * processor. 1242*400e64dfSOhad Ben-Cohen */ 1243*400e64dfSOhad Ben-Cohen int rproc_register(struct rproc *rproc) 1244*400e64dfSOhad Ben-Cohen { 1245*400e64dfSOhad Ben-Cohen struct device *dev = rproc->dev; 1246*400e64dfSOhad Ben-Cohen int ret = 0; 1247*400e64dfSOhad Ben-Cohen 1248*400e64dfSOhad Ben-Cohen /* expose to rproc_get_by_name users */ 1249*400e64dfSOhad Ben-Cohen klist_add_tail(&rproc->node, &rprocs); 1250*400e64dfSOhad Ben-Cohen 1251*400e64dfSOhad Ben-Cohen dev_info(rproc->dev, "%s is available\n", rproc->name); 1252*400e64dfSOhad Ben-Cohen 1253*400e64dfSOhad Ben-Cohen /* create debugfs entries */ 1254*400e64dfSOhad Ben-Cohen rproc_create_debug_dir(rproc); 1255*400e64dfSOhad Ben-Cohen 1256*400e64dfSOhad Ben-Cohen /* rproc_unregister() calls must wait until async loader completes */ 1257*400e64dfSOhad Ben-Cohen init_completion(&rproc->firmware_loading_complete); 1258*400e64dfSOhad Ben-Cohen 1259*400e64dfSOhad Ben-Cohen /* 1260*400e64dfSOhad Ben-Cohen * We must retrieve early virtio configuration info from 1261*400e64dfSOhad Ben-Cohen * the firmware (e.g. whether to register a virtio rpmsg device, 1262*400e64dfSOhad Ben-Cohen * what virtio features does it support, ...). 1263*400e64dfSOhad Ben-Cohen * 1264*400e64dfSOhad Ben-Cohen * We're initiating an asynchronous firmware loading, so we can 1265*400e64dfSOhad Ben-Cohen * be built-in kernel code, without hanging the boot process. 1266*400e64dfSOhad Ben-Cohen */ 1267*400e64dfSOhad Ben-Cohen ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, 1268*400e64dfSOhad Ben-Cohen rproc->firmware, dev, GFP_KERNEL, 1269*400e64dfSOhad Ben-Cohen rproc, rproc_fw_config_virtio); 1270*400e64dfSOhad Ben-Cohen if (ret < 0) { 1271*400e64dfSOhad Ben-Cohen dev_err(dev, "request_firmware_nowait failed: %d\n", ret); 1272*400e64dfSOhad Ben-Cohen complete_all(&rproc->firmware_loading_complete); 1273*400e64dfSOhad Ben-Cohen klist_remove(&rproc->node); 1274*400e64dfSOhad Ben-Cohen } 1275*400e64dfSOhad Ben-Cohen 1276*400e64dfSOhad Ben-Cohen return ret; 1277*400e64dfSOhad Ben-Cohen } 1278*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_register); 1279*400e64dfSOhad Ben-Cohen 1280*400e64dfSOhad Ben-Cohen /** 1281*400e64dfSOhad Ben-Cohen * rproc_alloc() - allocate a remote processor handle 1282*400e64dfSOhad Ben-Cohen * @dev: the underlying device 1283*400e64dfSOhad Ben-Cohen * @name: name of this remote processor 1284*400e64dfSOhad Ben-Cohen * @ops: platform-specific handlers (mainly start/stop) 1285*400e64dfSOhad Ben-Cohen * @firmware: name of firmware file to load 1286*400e64dfSOhad Ben-Cohen * @len: length of private data needed by the rproc driver (in bytes) 1287*400e64dfSOhad Ben-Cohen * 1288*400e64dfSOhad Ben-Cohen * Allocates a new remote processor handle, but does not register 1289*400e64dfSOhad Ben-Cohen * it yet. 1290*400e64dfSOhad Ben-Cohen * 1291*400e64dfSOhad Ben-Cohen * This function should be used by rproc implementations during initialization 1292*400e64dfSOhad Ben-Cohen * of the remote processor. 1293*400e64dfSOhad Ben-Cohen * 1294*400e64dfSOhad Ben-Cohen * After creating an rproc handle using this function, and when ready, 1295*400e64dfSOhad Ben-Cohen * implementations should then call rproc_register() to complete 1296*400e64dfSOhad Ben-Cohen * the registration of the remote processor. 1297*400e64dfSOhad Ben-Cohen * 1298*400e64dfSOhad Ben-Cohen * On success the new rproc is returned, and on failure, NULL. 1299*400e64dfSOhad Ben-Cohen * 1300*400e64dfSOhad Ben-Cohen * Note: _never_ directly deallocate @rproc, even if it was not registered 1301*400e64dfSOhad Ben-Cohen * yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free(). 1302*400e64dfSOhad Ben-Cohen */ 1303*400e64dfSOhad Ben-Cohen struct rproc *rproc_alloc(struct device *dev, const char *name, 1304*400e64dfSOhad Ben-Cohen const struct rproc_ops *ops, 1305*400e64dfSOhad Ben-Cohen const char *firmware, int len) 1306*400e64dfSOhad Ben-Cohen { 1307*400e64dfSOhad Ben-Cohen struct rproc *rproc; 1308*400e64dfSOhad Ben-Cohen 1309*400e64dfSOhad Ben-Cohen if (!dev || !name || !ops) 1310*400e64dfSOhad Ben-Cohen return NULL; 1311*400e64dfSOhad Ben-Cohen 1312*400e64dfSOhad Ben-Cohen rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL); 1313*400e64dfSOhad Ben-Cohen if (!rproc) { 1314*400e64dfSOhad Ben-Cohen dev_err(dev, "%s: kzalloc failed\n", __func__); 1315*400e64dfSOhad Ben-Cohen return NULL; 1316*400e64dfSOhad Ben-Cohen } 1317*400e64dfSOhad Ben-Cohen 1318*400e64dfSOhad Ben-Cohen rproc->dev = dev; 1319*400e64dfSOhad Ben-Cohen rproc->name = name; 1320*400e64dfSOhad Ben-Cohen rproc->ops = ops; 1321*400e64dfSOhad Ben-Cohen rproc->firmware = firmware; 1322*400e64dfSOhad Ben-Cohen rproc->priv = &rproc[1]; 1323*400e64dfSOhad Ben-Cohen 1324*400e64dfSOhad Ben-Cohen atomic_set(&rproc->power, 0); 1325*400e64dfSOhad Ben-Cohen 1326*400e64dfSOhad Ben-Cohen kref_init(&rproc->refcount); 1327*400e64dfSOhad Ben-Cohen 1328*400e64dfSOhad Ben-Cohen mutex_init(&rproc->lock); 1329*400e64dfSOhad Ben-Cohen 1330*400e64dfSOhad Ben-Cohen INIT_LIST_HEAD(&rproc->carveouts); 1331*400e64dfSOhad Ben-Cohen INIT_LIST_HEAD(&rproc->mappings); 1332*400e64dfSOhad Ben-Cohen INIT_LIST_HEAD(&rproc->traces); 1333*400e64dfSOhad Ben-Cohen 1334*400e64dfSOhad Ben-Cohen rproc->state = RPROC_OFFLINE; 1335*400e64dfSOhad Ben-Cohen 1336*400e64dfSOhad Ben-Cohen return rproc; 1337*400e64dfSOhad Ben-Cohen } 1338*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_alloc); 1339*400e64dfSOhad Ben-Cohen 1340*400e64dfSOhad Ben-Cohen /** 1341*400e64dfSOhad Ben-Cohen * rproc_free() - free an rproc handle that was allocated by rproc_alloc 1342*400e64dfSOhad Ben-Cohen * @rproc: the remote processor handle 1343*400e64dfSOhad Ben-Cohen * 1344*400e64dfSOhad Ben-Cohen * This function should _only_ be used if @rproc was only allocated, 1345*400e64dfSOhad Ben-Cohen * but not registered yet. 1346*400e64dfSOhad Ben-Cohen * 1347*400e64dfSOhad Ben-Cohen * If @rproc was already successfully registered (by calling rproc_register()), 1348*400e64dfSOhad Ben-Cohen * then use rproc_unregister() instead. 1349*400e64dfSOhad Ben-Cohen */ 1350*400e64dfSOhad Ben-Cohen void rproc_free(struct rproc *rproc) 1351*400e64dfSOhad Ben-Cohen { 1352*400e64dfSOhad Ben-Cohen kfree(rproc); 1353*400e64dfSOhad Ben-Cohen } 1354*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_free); 1355*400e64dfSOhad Ben-Cohen 1356*400e64dfSOhad Ben-Cohen /** 1357*400e64dfSOhad Ben-Cohen * rproc_unregister() - unregister a remote processor 1358*400e64dfSOhad Ben-Cohen * @rproc: rproc handle to unregister 1359*400e64dfSOhad Ben-Cohen * 1360*400e64dfSOhad Ben-Cohen * Unregisters a remote processor, and decrements its refcount. 1361*400e64dfSOhad Ben-Cohen * If its refcount drops to zero, then @rproc will be freed. If not, 1362*400e64dfSOhad Ben-Cohen * it will be freed later once the last reference is dropped. 1363*400e64dfSOhad Ben-Cohen * 1364*400e64dfSOhad Ben-Cohen * This function should be called when the platform specific rproc 1365*400e64dfSOhad Ben-Cohen * implementation decides to remove the rproc device. it should 1366*400e64dfSOhad Ben-Cohen * _only_ be called if a previous invocation of rproc_register() 1367*400e64dfSOhad Ben-Cohen * has completed successfully. 1368*400e64dfSOhad Ben-Cohen * 1369*400e64dfSOhad Ben-Cohen * After rproc_unregister() returns, @rproc is _not_ valid anymore and 1370*400e64dfSOhad Ben-Cohen * it shouldn't be used. More specifically, don't call rproc_free() 1371*400e64dfSOhad Ben-Cohen * or try to directly free @rproc after rproc_unregister() returns; 1372*400e64dfSOhad Ben-Cohen * none of these are needed, and calling them is a bug. 1373*400e64dfSOhad Ben-Cohen * 1374*400e64dfSOhad Ben-Cohen * Returns 0 on success and -EINVAL if @rproc isn't valid. 1375*400e64dfSOhad Ben-Cohen */ 1376*400e64dfSOhad Ben-Cohen int rproc_unregister(struct rproc *rproc) 1377*400e64dfSOhad Ben-Cohen { 1378*400e64dfSOhad Ben-Cohen if (!rproc) 1379*400e64dfSOhad Ben-Cohen return -EINVAL; 1380*400e64dfSOhad Ben-Cohen 1381*400e64dfSOhad Ben-Cohen /* if rproc is just being registered, wait */ 1382*400e64dfSOhad Ben-Cohen wait_for_completion(&rproc->firmware_loading_complete); 1383*400e64dfSOhad Ben-Cohen 1384*400e64dfSOhad Ben-Cohen /* was an rpmsg vdev created ? */ 1385*400e64dfSOhad Ben-Cohen if (rproc->rvdev) 1386*400e64dfSOhad Ben-Cohen rproc_remove_rpmsg_vdev(rproc); 1387*400e64dfSOhad Ben-Cohen 1388*400e64dfSOhad Ben-Cohen klist_remove(&rproc->node); 1389*400e64dfSOhad Ben-Cohen 1390*400e64dfSOhad Ben-Cohen kref_put(&rproc->refcount, rproc_release); 1391*400e64dfSOhad Ben-Cohen 1392*400e64dfSOhad Ben-Cohen return 0; 1393*400e64dfSOhad Ben-Cohen } 1394*400e64dfSOhad Ben-Cohen EXPORT_SYMBOL(rproc_unregister); 1395*400e64dfSOhad Ben-Cohen 1396*400e64dfSOhad Ben-Cohen static int __init remoteproc_init(void) 1397*400e64dfSOhad Ben-Cohen { 1398*400e64dfSOhad Ben-Cohen rproc_init_debugfs(); 1399*400e64dfSOhad Ben-Cohen return 0; 1400*400e64dfSOhad Ben-Cohen } 1401*400e64dfSOhad Ben-Cohen module_init(remoteproc_init); 1402*400e64dfSOhad Ben-Cohen 1403*400e64dfSOhad Ben-Cohen static void __exit remoteproc_exit(void) 1404*400e64dfSOhad Ben-Cohen { 1405*400e64dfSOhad Ben-Cohen rproc_exit_debugfs(); 1406*400e64dfSOhad Ben-Cohen } 1407*400e64dfSOhad Ben-Cohen module_exit(remoteproc_exit); 1408*400e64dfSOhad Ben-Cohen 1409*400e64dfSOhad Ben-Cohen MODULE_LICENSE("GPL v2"); 1410*400e64dfSOhad Ben-Cohen MODULE_DESCRIPTION("Generic Remote Processor Framework"); 1411