X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fremoteproc%2Fremoteproc_core.c;h=9e03d158f4119133f09b0979d8b5b70e1ae63c06;hb=e09b41010ba33a20a87472ee821fa407a5b8da36;hp=11cdb119e4f3bbdee5d73293dd71cec450f2ae65;hpb=f93b97fd65072de626c074dbe099a1fff05ce060;p=kvmfornfv.git diff --git a/kernel/drivers/remoteproc/remoteproc_core.c b/kernel/drivers/remoteproc/remoteproc_core.c index 11cdb119e..9e03d158f 100644 --- a/kernel/drivers/remoteproc/remoteproc_core.c +++ b/kernel/drivers/remoteproc/remoteproc_core.c @@ -44,6 +44,9 @@ #include "remoteproc_internal.h" +static DEFINE_MUTEX(rproc_list_mutex); +static LIST_HEAD(rproc_list); + typedef int (*rproc_handle_resources_t)(struct rproc *rproc, struct resource_table *table, int len); typedef int (*rproc_handle_resource_t)(struct rproc *rproc, @@ -132,32 +135,48 @@ static void rproc_disable_iommu(struct rproc *rproc) iommu_detach_device(domain, dev); iommu_domain_free(domain); - - return; } -/* +/** + * rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address + * @rproc: handle of a remote processor + * @da: remoteproc device address to translate + * @len: length of the memory region @da is pointing to + * * Some remote processors will ask us to allocate them physically contiguous * memory regions (which we call "carveouts"), and map them to specific - * device addresses (which are hardcoded in the firmware). + * device addresses (which are hardcoded in the firmware). They may also have + * dedicated memory regions internal to the processors, and use them either + * exclusively or alongside carveouts. * * They may then ask us to copy objects into specific device addresses (e.g. * code/data sections) or expose us certain symbols in other device address * (e.g. their trace buffer). * - * This function is an internal helper with which we can go over the allocated - * carveouts and translate specific device address to kernel virtual addresses - * so we can access the referenced memory. + * This function is a helper function with which we can go over the allocated + * carveouts and translate specific device addresses to kernel virtual addresses + * so we can access the referenced memory. This function also allows to perform + * translations on the internal remoteproc memory regions through a platform + * implementation specific da_to_va ops, if present. + * + * The function returns a valid kernel address on success or NULL on failure. * * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, * but only on kernel direct mapped RAM memory. Instead, we're just using - * here the output of the DMA API, which should be more correct. + * here the output of the DMA API for the carveouts, which should be more + * correct. */ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) { struct rproc_mem_entry *carveout; void *ptr = NULL; + if (rproc->ops->da_to_va) { + ptr = rproc->ops->da_to_va(rproc, da, len); + if (ptr) + goto out; + } + list_for_each_entry(carveout, &rproc->carveouts, node) { int offset = da - carveout->da; @@ -174,6 +193,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) break; } +out: return ptr; } EXPORT_SYMBOL(rproc_da_to_va); @@ -411,10 +431,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, } trace = kzalloc(sizeof(*trace), GFP_KERNEL); - if (!trace) { - dev_err(dev, "kzalloc trace failed\n"); + if (!trace) return -ENOMEM; - } /* set the trace buffer dma properties */ trace->len = rsc->len; @@ -489,10 +507,8 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, } mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); - if (!mapping) { - dev_err(dev, "kzalloc mapping failed\n"); + if (!mapping) return -ENOMEM; - } ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags); if (ret) { @@ -565,10 +581,8 @@ static int rproc_handle_carveout(struct rproc *rproc, rsc->da, rsc->pa, rsc->len, rsc->flags); carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); - if (!carveout) { - dev_err(dev, "kzalloc carveout failed\n"); + if (!carveout) return -ENOMEM; - } va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); if (!va) { @@ -768,7 +782,8 @@ static void rproc_resource_cleanup(struct rproc *rproc) /* clean up carveout allocations */ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { - dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma); + dma_free_coherent(dev->parent, entry->len, entry->va, + entry->dma); list_del(&entry->node); kfree(entry); } @@ -808,9 +823,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) /* look for the resource table */ table = rproc_find_rsc_table(rproc, fw, &tablesz); - if (!table) { + if (!table) goto clean_up; - } /* Verify that resource table in loaded fw is unchanged */ if (rproc->table_csum != crc32(0, table, tablesz)) { @@ -911,7 +925,8 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) /* count the number of notify-ids */ rproc->max_notifyid = -1; - ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); + ret = rproc_handle_resources(rproc, tablesz, + rproc_count_vrings_handler); if (ret) goto out; @@ -1151,6 +1166,50 @@ out: } EXPORT_SYMBOL(rproc_shutdown); +/** + * rproc_get_by_phandle() - find a remote processor by phandle + * @phandle: phandle to the rproc + * + * Finds an rproc handle using the remote processor's phandle, and then + * return a handle to the rproc. + * + * This function increments the remote processor's refcount, so always + * use rproc_put() to decrement it back once rproc isn't needed anymore. + * + * Returns the rproc handle on success, and NULL on failure. + */ +#ifdef CONFIG_OF +struct rproc *rproc_get_by_phandle(phandle phandle) +{ + struct rproc *rproc = NULL, *r; + struct device_node *np; + + np = of_find_node_by_phandle(phandle); + if (!np) + return NULL; + + mutex_lock(&rproc_list_mutex); + list_for_each_entry(r, &rproc_list, node) { + if (r->dev.parent && r->dev.parent->of_node == np) { + rproc = r; + get_device(&rproc->dev); + break; + } + } + mutex_unlock(&rproc_list_mutex); + + of_node_put(np); + + return rproc; +} +#else +struct rproc *rproc_get_by_phandle(phandle phandle) +{ + return NULL; +} +#endif +EXPORT_SYMBOL(rproc_get_by_phandle); + /** * rproc_add() - register a remote processor * @rproc: the remote processor handle to register @@ -1180,6 +1239,11 @@ int rproc_add(struct rproc *rproc) if (ret < 0) return ret; + /* expose to rproc_get_by_phandle users */ + mutex_lock(&rproc_list_mutex); + list_add(&rproc->node, &rproc_list); + mutex_unlock(&rproc_list_mutex); + dev_info(dev, "%s is available\n", rproc->name); dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n"); @@ -1268,10 +1332,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, name_len = strlen(name) + strlen(template) - 2 + 1; rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL); - if (!rproc) { - dev_err(dev, "%s: kzalloc failed\n", __func__); + if (!rproc) return NULL; - } if (!firmware) { p = (char *)rproc + sizeof(struct rproc) + len; @@ -1369,6 +1431,11 @@ int rproc_del(struct rproc *rproc) /* Free the copy of the resource table */ kfree(rproc->cached_table); + /* the rproc is downref'ed as soon as it's removed from the klist */ + mutex_lock(&rproc_list_mutex); + list_del(&rproc->node); + mutex_unlock(&rproc_list_mutex); + device_del(&rproc->dev); return 0; @@ -1411,6 +1478,8 @@ module_init(remoteproc_init); static void __exit remoteproc_exit(void) { + ida_destroy(&rproc_dev_index); + rproc_exit_debugfs(); } module_exit(remoteproc_exit);