From f665b2cd3f569a353c0a62b03a95827dd8743e9b Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:33 +0100 Subject: remoteproc: refactor rproc_elf_find_rsc_table() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor rproc_elf_find_rsc_table() and split out the scanning for the section header named resource table. This is done to prepare for loading firmware once. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [small function name change to make the code easier to read] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_elf_loader.c | 75 ++++++++++++++++++------------ 1 file changed, 46 insertions(+), 29 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 0d36f94ab51d..774e5f768bf3 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -208,41 +208,22 @@ rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) return ret; } -/** - * rproc_elf_find_rsc_table() - find the resource table - * @rproc: the rproc handle - * @fw: the ELF firmware image - * @tablesz: place holder for providing back the table size - * - * This function finds the resource table inside the remote processor's - * firmware. It is used both upon the registration of @rproc (in order - * to look for and register the supported virito devices), and when the - * @rproc is booted. - * - * Returns the pointer to the resource table if it is found, and write its - * size into @tablesz. If a valid table isn't found, NULL is returned - * (and @tablesz isn't set). - */ -static struct resource_table * -rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, - int *tablesz) +static struct elf32_shdr * +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size) { - struct elf32_hdr *ehdr; struct elf32_shdr *shdr; + int i; const char *name_table; - struct device *dev = &rproc->dev; struct resource_table *table = NULL; - int i; - const u8 *elf_data = fw->data; + const u8 *elf_data = (void *)ehdr; - ehdr = (struct elf32_hdr *)elf_data; + /* look for the resource table and handle it */ shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset; - /* look for the resource table and handle it */ for (i = 0; i < ehdr->e_shnum; i++, shdr++) { - int size = shdr->sh_size; - int offset = shdr->sh_offset; + u32 size = shdr->sh_size; + u32 offset = shdr->sh_offset; if (strcmp(name_table + shdr->sh_name, ".resource_table")) continue; @@ -250,7 +231,7 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, table = (struct resource_table *)(elf_data + offset); /* make sure we have the entire table */ - if (offset + size > fw->size) { + if (offset + size > fw_size || offset + size < size) { dev_err(dev, "resource table truncated\n"); return NULL; } @@ -280,10 +261,46 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, return NULL; } - *tablesz = shdr->sh_size; - break; + return shdr; } + return NULL; +} + +/** + * rproc_elf_find_rsc_table() - find the resource table + * @rproc: the rproc handle + * @fw: the ELF firmware image + * @tablesz: place holder for providing back the table size + * + * This function finds the resource table inside the remote processor's + * firmware. It is used both upon the registration of @rproc (in order + * to look for and register the supported virito devices), and when the + * @rproc is booted. + * + * Returns the pointer to the resource table if it is found, and write its + * size into @tablesz. If a valid table isn't found, NULL is returned + * (and @tablesz isn't set). + */ +static struct resource_table * +rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, + int *tablesz) +{ + struct elf32_hdr *ehdr; + struct elf32_shdr *shdr; + struct device *dev = &rproc->dev; + struct resource_table *table = NULL; + const u8 *elf_data = fw->data; + + ehdr = (struct elf32_hdr *)elf_data; + + shdr = find_table(dev, ehdr, fw->size); + if (!shdr) + return NULL; + + table = (struct resource_table *)(elf_data + shdr->sh_offset); + *tablesz = shdr->sh_size; + return table; } -- cgit v1.2.3-59-g8ed1b From 95f9578163bc25bcbf391420373cf797d5321830 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:34 +0100 Subject: remoteproc: add find_loaded_rsc_table firmware ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add function find_loaded_rsc_table to firmware ops. This function returns the location of the resource table in shared memory after loading. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [align function name with existing terminology, update commit log] [document new function, rebase patch, small cleanups] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_elf_loader.c | 25 +++++++++++++++++++++++++ drivers/remoteproc/remoteproc_internal.h | 15 ++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 774e5f768bf3..ce283a5b42a1 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -304,9 +304,34 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw, return table; } +/** + * rproc_elf_find_loaded_rsc_table() - find the loaded resource table + * @rproc: the rproc handle + * @fw: the ELF firmware image + * + * This function finds the location of the loaded resource table. Don't + * call this function if the table wasn't loaded yet - it's a bug if you do. + * + * Returns the pointer to the resource table if it is found or NULL otherwise. + * If the table wasn't loaded yet the result is unspecified. + */ +static struct resource_table * +rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw) +{ + struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data; + struct elf32_shdr *shdr; + + shdr = find_table(&rproc->dev, ehdr, fw->size); + if (!shdr) + return NULL; + + return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size); +} + const struct rproc_fw_ops rproc_elf_fw_ops = { .load = rproc_elf_load_segments, .find_rsc_table = rproc_elf_find_rsc_table, + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr }; diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 7bb66482d061..157e762c1571 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -27,7 +27,8 @@ struct rproc; /** * struct rproc_fw_ops - firmware format specific operations. - * @find_rsc_table: finds the resource table inside the firmware image + * @find_rsc_table: find the resource table inside the firmware image + * @find_loaded_rsc_table: find the loaded resouce table * @load: load firmeware to memory, where the remote processor * expects to find it * @sanity_check: sanity check the fw image @@ -37,6 +38,8 @@ struct rproc_fw_ops { struct resource_table *(*find_rsc_table) (struct rproc *rproc, const struct firmware *fw, int *tablesz); + struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc, + const struct firmware *fw); int (*load)(struct rproc *rproc, const struct firmware *fw); int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); @@ -102,6 +105,16 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc, return NULL; } +static inline +struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc, + const struct firmware *fw) +{ + if (rproc->fw_ops->find_loaded_rsc_table) + return rproc->fw_ops->find_loaded_rsc_table(rproc, fw); + + return NULL; +} + extern const struct rproc_fw_ops rproc_elf_fw_ops; #endif /* REMOTEPROC_INTERNAL_H */ -- cgit v1.2.3-59-g8ed1b From e4b51414813faf5cdc89e373b2e44cdbead09459 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:35 +0100 Subject: remoteproc: parse STE-firmware and find resource table address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parse the STE firmware and scan the TOC-table to find the address of the loaded resource table. Signed-off-by: Sjur Brændeland [rebase patch; update terminology] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/ste_modem_rproc.c | 43 ++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c index a7743c069339..8cc588f38cd2 100644 --- a/drivers/remoteproc/ste_modem_rproc.c +++ b/drivers/remoteproc/ste_modem_rproc.c @@ -64,26 +64,18 @@ static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw) } /* Find the entry for resource table in the Table of Content */ -static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw) +static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data) { int i; - struct ste_toc *toc; - - if (!fw) - return NULL; - - toc = (void *)fw->data; + const struct ste_toc *toc; + toc = data; /* Search the table for the resource table */ for (i = 0; i < SPROC_MAX_TOC_ENTRIES && toc->table[i].start != 0xffffffff; i++) { - if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME, - sizeof(toc->table[i].name))) { - if (toc->table[i].start > fw->size) - return NULL; + sizeof(toc->table[i].name))) return &toc->table[i]; - } } return NULL; @@ -96,9 +88,12 @@ sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw, { struct sproc *sproc = rproc->priv; struct resource_table *table; - struct ste_toc_entry *entry; + const struct ste_toc_entry *entry; - entry = sproc_find_rsc_entry(fw); + if (!fw) + return NULL; + + entry = sproc_find_rsc_entry(fw->data); if (!entry) { sproc_err(sproc, "resource table not found in fw\n"); return NULL; @@ -149,10 +144,30 @@ sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw, return table; } +/* Find the resource table inside the remote processor's firmware. */ +static struct resource_table * +sproc_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw) +{ + struct sproc *sproc = rproc->priv; + const struct ste_toc_entry *entry; + + if (!fw || !sproc->fw_addr) + return NULL; + + entry = sproc_find_rsc_entry(sproc->fw_addr); + if (!entry) { + sproc_err(sproc, "resource table not found in fw\n"); + return NULL; + } + + return sproc->fw_addr + entry->start; +} + /* STE modem firmware handler operations */ const struct rproc_fw_ops sproc_fw_ops = { .load = sproc_load_segments, .find_rsc_table = sproc_find_rsc_table, + .find_loaded_rsc_table = sproc_find_loaded_rsc_table, }; /* Kick the modem with specified notification id */ -- cgit v1.2.3-59-g8ed1b From 232fcdbb450000850bef8ff7e022cde2b4053f67 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:36 +0100 Subject: remoteproc: code cleanup of resource parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combine the almost identical functions rproc_handle_virtio_rsc and rproc_handle_boot_rsc. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [small terminology and style changes] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 52 +++++++++--------------------------- 1 file changed, 12 insertions(+), 40 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 29387df4bfc9..b8228c628b0c 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -673,16 +673,21 @@ free_carv: * A lookup table for resource handlers. The indices are defined in * enum fw_resource_type. */ -static rproc_handle_resource_t rproc_handle_rsc[] = { +static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */ }; +static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { + [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, +}; + /* handle firmware resource entries before booting the remote processor */ -static int -rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len) +static int rproc_handle_resources(struct rproc *rproc, + struct resource_table *table, int len, + rproc_handle_resource_t handlers[RSC_LAST]) { struct device *dev = &rproc->dev; rproc_handle_resource_t handler; @@ -707,7 +712,7 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len continue; } - handler = rproc_handle_rsc[hdr->type]; + handler = handlers[hdr->type]; if (!handler) continue; @@ -719,40 +724,6 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len return ret; } -/* handle firmware resource entries while registering the remote processor */ -static int -rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len) -{ - struct device *dev = &rproc->dev; - int ret = 0, i; - - for (i = 0; i < table->num; i++) { - int offset = table->offset[i]; - struct fw_rsc_hdr *hdr = (void *)table + offset; - int avail = len - offset - sizeof(*hdr); - struct fw_rsc_vdev *vrsc; - - /* make sure table isn't truncated */ - if (avail < 0) { - dev_err(dev, "rsc table is truncated\n"); - return -EINVAL; - } - - dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type); - - if (hdr->type != RSC_VDEV) - continue; - - vrsc = (struct fw_rsc_vdev *)hdr->data; - - ret = rproc_handle_vdev(rproc, vrsc, avail); - if (ret) - break; - } - - return ret; -} - /** * rproc_resource_cleanup() - clean up and free all acquired resources * @rproc: rproc handle @@ -832,7 +803,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) } /* handle fw resources which are required to boot rproc */ - ret = rproc_handle_boot_rsc(rproc, table, tablesz); + ret = rproc_handle_resources(rproc, table, tablesz, + rproc_loading_handlers); if (ret) { dev_err(dev, "Failed to process resources: %d\n", ret); goto clean_up; @@ -887,7 +859,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) goto out; /* look for virtio devices and register them */ - ret = rproc_handle_virtio_rsc(rproc, table, tablesz); + ret = rproc_handle_resources(rproc, table, tablesz, rproc_vdev_handler); if (ret) goto out; -- cgit v1.2.3-59-g8ed1b From ba7290e01663787fcfc2bedaff6232359d4ff248 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:37 +0100 Subject: remoteproc: calculate max_notifyid by counting vrings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify handling of max_notifyid by simply counting the number of vrings. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [small terminology changes] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 33 ++++++++++++++++++--------------- drivers/remoteproc/ste_modem_rproc.c | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index b8228c628b0c..9d2a4ac6c706 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -224,9 +224,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) } notifyid = ret; - /* Store largest notifyid */ - rproc->max_notifyid = max(rproc->max_notifyid, notifyid); - dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va, (unsigned long long)dma, size, notifyid); @@ -268,25 +265,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) return 0; } -static int rproc_max_notifyid(int id, void *p, void *data) -{ - int *maxid = data; - *maxid = max(*maxid, id); - return 0; -} - void rproc_free_vring(struct rproc_vring *rvring) { int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); struct rproc *rproc = rvring->rvdev->rproc; - int maxid = 0; dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); idr_remove(&rproc->notifyids, rvring->notifyid); - - /* Find the largest remaining notifyid */ - idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid); - rproc->max_notifyid = maxid; } /** @@ -669,6 +654,15 @@ free_carv: return ret; } +static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc, + int avail) +{ + /* Summarize the number of notification IDs */ + rproc->max_notifyid += rsc->num_of_vrings; + + return 0; +} + /* * A lookup table for resource handlers. The indices are defined in * enum fw_resource_type. @@ -684,6 +678,10 @@ static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, }; +static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = { + [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings, +}; + /* handle firmware resource entries before booting the remote processor */ static int rproc_handle_resources(struct rproc *rproc, struct resource_table *table, int len, @@ -858,6 +856,11 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) if (!table) goto out; + /* count the number of notify-ids */ + rproc->max_notifyid = -1; + ret = rproc_handle_resources(rproc, table, tablesz, + rproc_count_vrings_handler); + /* look for virtio devices and register them */ ret = rproc_handle_resources(rproc, table, tablesz, rproc_vdev_handler); if (ret) diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c index 8cc588f38cd2..6fc213948146 100644 --- a/drivers/remoteproc/ste_modem_rproc.c +++ b/drivers/remoteproc/ste_modem_rproc.c @@ -213,7 +213,7 @@ static int sproc_start(struct rproc *rproc) } /* Subscribe to notifications */ - for (i = 0; i < rproc->max_notifyid; i++) { + for (i = 0; i <= rproc->max_notifyid; i++) { err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i); if (err) { sproc_err(sproc, -- cgit v1.2.3-59-g8ed1b From a2b950ac7b1e6442919ee9e79c4963e134698869 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 7 Apr 2013 14:06:07 +0300 Subject: remoteproc: perserve resource table data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copy resource table from first to second firmware loading. After firmware is loaded to memory, update the vdevs resource pointer to the resource table kept in device memory. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [rebase, terminology and style changes] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 1 + drivers/remoteproc/remoteproc_core.c | 98 ++++++++++++++++++++++++++++-------- include/linux/remoteproc.h | 9 ++++ 3 files changed, 88 insertions(+), 20 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index cc1f7bf53fd0..289e867a77dd 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -4,6 +4,7 @@ menu "Remoteproc drivers" config REMOTEPROC tristate depends on HAS_DMA + select CRC32 select FW_CONFIG select VIRTIO diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9d2a4ac6c706..617b825aa553 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,8 @@ typedef int (*rproc_handle_resources_t)(struct rproc *rproc, struct resource_table *table, int len); -typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); +typedef int (*rproc_handle_resource_t)(struct rproc *rproc, + void *, int offset, int avail); /* Unique indices for remoteproc devices */ static DEFINE_IDA(rproc_dev_index); @@ -302,7 +304,7 @@ void rproc_free_vring(struct rproc_vring *rvring) * Returns 0 on success, or an appropriate error code otherwise */ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, - int avail) + int offset, int avail) { struct device *dev = &rproc->dev; struct rproc_vdev *rvdev; @@ -346,6 +348,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, /* remember the device features */ rvdev->dfeatures = rsc->dfeatures; + /* remember the resource offset*/ + rvdev->rsc_offset = offset; + list_add_tail(&rvdev->node, &rproc->rvdevs); /* it is now safe to add the virtio device */ @@ -377,7 +382,7 @@ free_rvdev: * Returns 0 on success, or an appropriate error code otherwise */ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, - int avail) + int offset, int avail) { struct rproc_mem_entry *trace; struct device *dev = &rproc->dev; @@ -459,7 +464,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, * are outside those ranges. */ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, - int avail) + int offset, int avail) { struct rproc_mem_entry *mapping; struct device *dev = &rproc->dev; @@ -532,7 +537,9 @@ out: * pressure is important; it may have a substantial impact on performance. */ static int rproc_handle_carveout(struct rproc *rproc, - struct fw_rsc_carveout *rsc, int avail) + struct fw_rsc_carveout *rsc, + int offset, int avail) + { struct rproc_mem_entry *carveout, *mapping; struct device *dev = &rproc->dev; @@ -655,7 +662,7 @@ free_carv: } static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc, - int avail) + int offset, int avail) { /* Summarize the number of notification IDs */ rproc->max_notifyid += rsc->num_of_vrings; @@ -683,17 +690,16 @@ static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = { }; /* handle firmware resource entries before booting the remote processor */ -static int rproc_handle_resources(struct rproc *rproc, - struct resource_table *table, int len, +static int rproc_handle_resources(struct rproc *rproc, int len, rproc_handle_resource_t handlers[RSC_LAST]) { struct device *dev = &rproc->dev; rproc_handle_resource_t handler; int ret = 0, i; - for (i = 0; i < table->num; i++) { - int offset = table->offset[i]; - struct fw_rsc_hdr *hdr = (void *)table + offset; + for (i = 0; i < rproc->table_ptr->num; i++) { + int offset = rproc->table_ptr->offset[i]; + struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; int avail = len - offset - sizeof(*hdr); void *rsc = (void *)hdr + sizeof(*hdr); @@ -714,7 +720,7 @@ static int rproc_handle_resources(struct rproc *rproc, if (!handler) continue; - ret = handler(rproc, rsc, avail); + ret = handler(rproc, rsc, offset + sizeof(*hdr), avail); if (ret) break; } @@ -772,9 +778,12 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) { struct device *dev = &rproc->dev; const char *name = rproc->firmware; - struct resource_table *table; + struct resource_table *table, *loaded_table; int ret, tablesz; + if (!rproc->table_ptr) + return -ENOMEM; + ret = rproc_fw_sanity_check(rproc, fw); if (ret) return ret; @@ -800,9 +809,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) goto clean_up; } + /* Verify that resource table in loaded fw is unchanged */ + if (rproc->table_csum != crc32(0, table, tablesz)) { + dev_err(dev, "resource checksum failed, fw changed?\n"); + ret = -EINVAL; + goto clean_up; + } + /* handle fw resources which are required to boot rproc */ - ret = rproc_handle_resources(rproc, table, tablesz, - rproc_loading_handlers); + ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers); if (ret) { dev_err(dev, "Failed to process resources: %d\n", ret); goto clean_up; @@ -815,6 +830,19 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) goto clean_up; } + /* + * The starting device has been given the rproc->cached_table as the + * resource table. The address of the vring along with the other + * allocated resources (carveouts etc) is stored in cached_table. + * In order to pass this information to the remote device we must + * copy this information to device memory. + */ + loaded_table = rproc_find_loaded_rsc_table(rproc, fw); + if (!loaded_table) + goto clean_up; + + memcpy(loaded_table, rproc->cached_table, tablesz); + /* power up the remote processor */ ret = rproc->ops->start(rproc); if (ret) { @@ -822,6 +850,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) goto clean_up; } + /* + * Update table_ptr so that all subsequent vring allocations and + * virtio fields manipulation update the actual loaded resource table + * in device memory. + */ + rproc->table_ptr = loaded_table; + rproc->state = RPROC_RUNNING; dev_info(dev, "remote processor %s is now up\n", rproc->name); @@ -856,16 +891,30 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) if (!table) goto out; + rproc->table_csum = crc32(0, table, tablesz); + + /* + * Create a copy of the resource table. When a virtio device starts + * and calls vring_new_virtqueue() the address of the allocated vring + * will be stored in the cached_table. Before the device is started, + * cached_table will be copied into devic memory. + */ + rproc->cached_table = kmalloc(tablesz, GFP_KERNEL); + if (!rproc->cached_table) + goto out; + + memcpy(rproc->cached_table, table, tablesz); + rproc->table_ptr = rproc->cached_table; + /* count the number of notify-ids */ rproc->max_notifyid = -1; - ret = rproc_handle_resources(rproc, table, tablesz, - rproc_count_vrings_handler); - - /* look for virtio devices and register them */ - ret = rproc_handle_resources(rproc, table, tablesz, rproc_vdev_handler); + ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); if (ret) goto out; + /* look for virtio devices and register them */ + ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler); + out: release_firmware(fw); /* allow rproc_del() contexts, if any, to proceed */ @@ -923,6 +972,9 @@ int rproc_trigger_recovery(struct rproc *rproc) /* wait until there is no more rproc users */ wait_for_completion(&rproc->crash_comp); + /* Free the copy of the resource table */ + kfree(rproc->cached_table); + return rproc_add_virtio_devices(rproc); } @@ -1078,6 +1130,9 @@ void rproc_shutdown(struct rproc *rproc) rproc_disable_iommu(rproc); + /* Give the next start a clean resource table */ + rproc->table_ptr = rproc->cached_table; + /* if in crash state, unlock crash handler */ if (rproc->state == RPROC_CRASHED) complete_all(&rproc->crash_comp); @@ -1288,6 +1343,9 @@ int rproc_del(struct rproc *rproc) list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) rproc_remove_virtio_dev(rvdev); + /* Free the copy of the resource table */ + kfree(rproc->cached_table); + device_del(&rproc->dev); return 0; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index faf33324c78f..b4cef16460f8 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -401,6 +401,9 @@ enum rproc_crash_type { * @crash_comp: completion used to sync crash handler and the rproc reload * @recovery_disabled: flag that state if recovery was disabled * @max_notifyid: largest allocated notify id. + * @table_ptr: pointer to the resource table in effect + * @cached_table: copy of the resource table + * @table_csum: checksum of the resource table */ struct rproc { struct klist_node node; @@ -429,9 +432,13 @@ struct rproc { struct completion crash_comp; bool recovery_disabled; int max_notifyid; + struct resource_table *table_ptr; + struct resource_table *cached_table; + u32 table_csum; }; /* we currently support only two vrings per rvdev */ + #define RVDEV_NUM_VRINGS 2 /** @@ -464,6 +471,7 @@ struct rproc_vring { * @vring: the vrings for this vdev * @dfeatures: virtio device features * @gfeatures: virtio guest features + * @rsc_offset: offset of the vdev's resource entry */ struct rproc_vdev { struct list_head node; @@ -472,6 +480,7 @@ struct rproc_vdev { struct rproc_vring vring[RVDEV_NUM_VRINGS]; unsigned long dfeatures; unsigned long gfeatures; + u32 rsc_offset; }; struct rproc *rproc_alloc(struct device *dev, const char *name, -- cgit v1.2.3-59-g8ed1b From 92b38f851470f8d8ea7ed638d546f83b5268bc12 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:39 +0100 Subject: remoteproc: support virtio config space. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support virtio configuration space and device status. The virtio device can now access the resource table in shared memory. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [rebase and style changes] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 3 -- drivers/remoteproc/remoteproc_virtio.c | 79 +++++++++++++++++++++++++++------- include/linux/remoteproc.h | 4 -- 3 files changed, 64 insertions(+), 22 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 617b825aa553..d0251fe9e119 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -345,9 +345,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, goto free_rvdev; } - /* remember the device features */ - rvdev->dfeatures = rsc->dfeatures; - /* remember the resource offset*/ rvdev->rsc_offset = offset; diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index afed9b7731c4..b09c75c21b60 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -173,25 +173,35 @@ error: return ret; } -/* - * We don't support yet real virtio status semantics. - * - * The plan is to provide this via the VDEV resource entry - * which is part of the firmware: this way the remote processor - * will be able to access the status values as set by us. - */ static u8 rproc_virtio_get_status(struct virtio_device *vdev) { - return 0; + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; + + return rsc->status; } static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status) { + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; + + rsc->status = status; dev_dbg(&vdev->dev, "status: %d\n", status); } static void rproc_virtio_reset(struct virtio_device *vdev) { + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; + + rsc->status = 0; dev_dbg(&vdev->dev, "reset !\n"); } @@ -199,13 +209,19 @@ static void rproc_virtio_reset(struct virtio_device *vdev) static u32 rproc_virtio_get_features(struct virtio_device *vdev) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; - return rvdev->dfeatures; + return rsc->dfeatures; } static void rproc_virtio_finalize_features(struct virtio_device *vdev) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; /* Give virtio_ring a chance to accept features */ vring_transport_features(vdev); @@ -213,13 +229,44 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev) /* * Remember the finalized features of our vdev, and provide it * to the remote processor once it is powered on. - * - * Similarly to the status field, we don't expose yet the negotiated - * features to the remote processors at this point. This will be - * fixed as part of a small resource table overhaul and then an - * extension of the virtio resource entries. */ - rvdev->gfeatures = vdev->features[0]; + rsc->gfeatures = vdev->features[0]; +} + +static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, + void *buf, unsigned len) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + void *cfg; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; + cfg = &rsc->vring[rsc->num_of_vrings]; + + if (offset + len > rsc->config_len || offset + len < len) { + dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n"); + return; + } + + memcpy(buf, cfg + offset, len); +} + +static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset, + const void *buf, unsigned len) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct fw_rsc_vdev *rsc; + void *cfg; + + rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset; + cfg = &rsc->vring[rsc->num_of_vrings]; + + if (offset + len > rsc->config_len || offset + len < len) { + dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n"); + return; + } + + memcpy(cfg + offset, buf, len); } static const struct virtio_config_ops rproc_virtio_config_ops = { @@ -230,6 +277,8 @@ static const struct virtio_config_ops rproc_virtio_config_ops = { .reset = rproc_virtio_reset, .set_status = rproc_virtio_set_status, .get_status = rproc_virtio_get_status, + .get = rproc_virtio_get, + .set = rproc_virtio_set, }; /* diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index b4cef16460f8..9e7e745dac55 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -469,8 +469,6 @@ struct rproc_vring { * @rproc: the rproc handle * @vdev: the virio device * @vring: the vrings for this vdev - * @dfeatures: virtio device features - * @gfeatures: virtio guest features * @rsc_offset: offset of the vdev's resource entry */ struct rproc_vdev { @@ -478,8 +476,6 @@ struct rproc_vdev { struct rproc *rproc; struct virtio_device vdev; struct rproc_vring vring[RVDEV_NUM_VRINGS]; - unsigned long dfeatures; - unsigned long gfeatures; u32 rsc_offset; }; -- cgit v1.2.3-59-g8ed1b From c0d631570ad54a8561f5fc7023e96b5316c7fdb9 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Thu, 21 Feb 2013 18:15:40 +0100 Subject: remoteproc: set vring addresses in resource table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the vring addresses in the resource table so that the remote device can read the actual addresses used. Signed-off-by: Sjur Brændeland Acked-by: Ido Yariv [rebase] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index d0251fe9e119..7c357370083a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -194,6 +194,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) struct rproc *rproc = rvdev->rproc; struct device *dev = &rproc->dev; struct rproc_vring *rvring = &rvdev->vring[i]; + struct fw_rsc_vdev *rsc; dma_addr_t dma; void *va; int ret, size, notifyid; @@ -204,7 +205,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) /* * Allocate non-cacheable memory for the vring. In the future * this call will also configure the IOMMU for us - * TODO: let the rproc know the da of this vring */ va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL); if (!va) { @@ -215,7 +215,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) /* * Assign an rproc-wide unique index for this vring * TODO: assign a notifyid for rvdev updates as well - * TODO: let the rproc know the notifyid of this vring * TODO: support predefined notifyids (via resource table) */ ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); @@ -233,6 +232,15 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) rvring->dma = dma; rvring->notifyid = notifyid; + /* + * Let the rproc know the notifyid and da of this vring. + * Not all platforms use dma_alloc_coherent to automatically + * set up the iommu. In this case the device address (da) will + * hold the physical address and not the device address. + */ + rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; + rsc->vring[i].da = dma; + rsc->vring[i].notifyid = notifyid; return 0; } @@ -271,9 +279,16 @@ void rproc_free_vring(struct rproc_vring *rvring) { int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); struct rproc *rproc = rvring->rvdev->rproc; + int idx = rvring->rvdev->vring - rvring; + struct fw_rsc_vdev *rsc; dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); idr_remove(&rproc->notifyids, rvring->notifyid); + + /* reset resource entry info */ + rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset; + rsc->vring[idx].da = 0; + rsc->vring[idx].notifyid = -1; } /** -- cgit v1.2.3-59-g8ed1b From e5bc0294ca03a684f322a1a37538ebc3c121d86a Mon Sep 17 00:00:00 2001 From: Vincent Stehlé Date: Mon, 18 Feb 2013 12:06:52 +0100 Subject: remoteproc/omap: support OMAP5 too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows building remoteproc on OMAP5 too. Signed-off-by: Vincent Stehlé [edit commit log] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 289e867a77dd..5ad65710c4ff 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -11,7 +11,7 @@ config REMOTEPROC config OMAP_REMOTEPROC tristate "OMAP remoteproc support" depends on HAS_DMA - depends on ARCH_OMAP4 + depends on ARCH_OMAP4 || SOC_OMAP5 depends on OMAP_IOMMU depends on OMAP_MBOX_FWK select REMOTEPROC -- cgit v1.2.3-59-g8ed1b From 8b4aec9ac7b59754df9c594569af9ae8f456ee07 Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Thu, 28 Mar 2013 18:41:44 -0700 Subject: remoteproc: support default firmware name in rproc_alloc() If rproc_alloc isn't given a firmware name, look for a default one using the "rproc-%s-fw" template. Signed-off-by: Robert Tivy [add commit log, document change, use snprintf, minor style change] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 7c357370083a..56a0f8d6855b 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1236,11 +1236,11 @@ static struct device_type rproc_type = { * @dev: the underlying device * @name: name of this remote processor * @ops: platform-specific handlers (mainly start/stop) - * @firmware: name of firmware file to load + * @firmware: name of firmware file to load, can be NULL * @len: length of private data needed by the rproc driver (in bytes) * * Allocates a new remote processor handle, but does not register - * it yet. + * it yet. if @firmware is NULL, a default name is used. * * This function should be used by rproc implementations during initialization * of the remote processor. @@ -1259,19 +1259,39 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, const char *firmware, int len) { struct rproc *rproc; + char *p, *template = "rproc-%s-fw"; + int name_len = 0; if (!dev || !name || !ops) return NULL; - rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL); + if (!firmware) + /* + * Make room for default firmware name (minus %s plus '\0'). + * If the caller didn't pass in a firmware name then + * construct a default name. We're already glomming 'len' + * bytes onto the end of the struct rproc allocation, so do + * a few more for the default firmware name (but only if + * the caller doesn't pass one). + */ + 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__); return NULL; } + if (!firmware) { + p = (char *)rproc + sizeof(struct rproc) + len; + snprintf(p, name_len, template, name); + } else { + p = (char *)firmware; + } + + rproc->firmware = p; rproc->name = name; rproc->ops = ops; - rproc->firmware = firmware; rproc->priv = &rproc[1]; device_initialize(&rproc->dev); -- cgit v1.2.3-59-g8ed1b From 13be5432d8721d89cadae105663761f45f427842 Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Tue, 9 Apr 2013 14:20:21 -0700 Subject: remoteproc/davinci: add a remoteproc driver for OMAP-L13x DSP Adding a new remoteproc driver for OMAP-L13x DSP Signed-off-by: Robert Tivy [removed 'EXPERIMENTAL' and fixed some indentation issues] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 23 +++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/da8xx_remoteproc.c | 324 ++++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 drivers/remoteproc/da8xx_remoteproc.c (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 5ad65710c4ff..c3675ae3cc9e 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -39,4 +39,27 @@ config STE_MODEM_RPROC This can be either built-in or a loadable module. If unsure say N. +config DA8XX_REMOTEPROC + tristate "DA8xx/OMAP-L13x remoteproc support" + depends on ARCH_DAVINCI_DA8XX + select CMA + select REMOTEPROC + select RPMSG + help + Say y here to support DA8xx/OMAP-L13x remote processors via the + remote processor framework. + + You want to say y here in order to enable AMP + use-cases to run on your platform (multimedia codecs are + offloaded to remote DSP processors using this framework). + + This module controls the name of the firmware file that gets + loaded on the DSP. This file must reside in the /lib/firmware + directory. It can be specified via the module parameter + da8xx_fw_name=, and if not specified will default to + "rproc-dsp-fw". + + It's safe to say n here if you're not interested in multimedia + offloading. + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 391b65181c05..ac2ff75686d2 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -9,3 +9,4 @@ remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o +obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c new file mode 100644 index 000000000000..9b2e60afa1a6 --- /dev/null +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -0,0 +1,324 @@ +/* + * Remote processor machine-specific module for DA8XX + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for davinci_clk_reset_assert/deassert() */ + +#include "remoteproc_internal.h" + +static char *da8xx_fw_name; +module_param(da8xx_fw_name, charp, S_IRUGO); +MODULE_PARM_DESC(da8xx_fw_name, + "\n\t\tName of DSP firmware file in /lib/firmware" + " (if not specified defaults to 'rproc-dsp-fw')"); + +/* + * OMAP-L138 Technical References: + * http://www.ti.com/product/omap-l138 + */ +#define SYSCFG_CHIPSIG0 BIT(0) +#define SYSCFG_CHIPSIG1 BIT(1) +#define SYSCFG_CHIPSIG2 BIT(2) +#define SYSCFG_CHIPSIG3 BIT(3) +#define SYSCFG_CHIPSIG4 BIT(4) + +/** + * struct da8xx_rproc - da8xx remote processor instance state + * @rproc: rproc handle + * @dsp_clk: placeholder for platform's DSP clk + * @ack_fxn: chip-specific ack function for ack'ing irq + * @irq_data: ack_fxn function parameter + * @chipsig: virt ptr to DSP interrupt registers (CHIPSIG & CHIPSIG_CLR) + * @bootreg: virt ptr to DSP boot address register (HOST1CFG) + * @irq: irq # used by this instance + */ +struct da8xx_rproc { + struct rproc *rproc; + struct clk *dsp_clk; + void (*ack_fxn)(struct irq_data *data); + struct irq_data *irq_data; + void __iomem *chipsig; + void __iomem *bootreg; + int irq; +}; + +/** + * handle_event() - inbound virtqueue message workqueue function + * + * This function is registered as a kernel thread and is scheduled by the + * kernel handler. + */ +static irqreturn_t handle_event(int irq, void *p) +{ + struct rproc *rproc = (struct rproc *)p; + + /* Process incoming buffers on all our vrings */ + rproc_vq_interrupt(rproc, 0); + rproc_vq_interrupt(rproc, 1); + + return IRQ_HANDLED; +} + +/** + * da8xx_rproc_callback() - inbound virtqueue message handler + * + * This handler is invoked directly by the kernel whenever the remote + * core (DSP) has modified the state of a virtqueue. There is no + * "payload" message indicating the virtqueue index as is the case with + * mailbox-based implementations on OMAP4. As such, this handler "polls" + * each known virtqueue index for every invocation. + */ +static irqreturn_t da8xx_rproc_callback(int irq, void *p) +{ + struct rproc *rproc = (struct rproc *)p; + struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + u32 chipsig; + + chipsig = readl(drproc->chipsig); + if (chipsig & SYSCFG_CHIPSIG0) { + /* Clear interrupt level source */ + writel(SYSCFG_CHIPSIG0, drproc->chipsig + 4); + + /* + * ACK intr to AINTC. + * + * It has already been ack'ed by the kernel before calling + * this function, but since the ARM<->DSP interrupts in the + * CHIPSIG register are "level" instead of "pulse" variety, + * we need to ack it after taking down the level else we'll + * be called again immediately after returning. + */ + drproc->ack_fxn(drproc->irq_data); + + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + +static int da8xx_rproc_start(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + struct clk *dsp_clk = drproc->dsp_clk; + + /* hw requires the start (boot) address be on 1KB boundary */ + if (rproc->bootaddr & 0x3ff) { + dev_err(dev, "invalid boot address: must be aligned to 1KB\n"); + + return -EINVAL; + } + + writel(rproc->bootaddr, drproc->bootreg); + + clk_enable(dsp_clk); + davinci_clk_reset_deassert(dsp_clk); + + return 0; +} + +static int da8xx_rproc_stop(struct rproc *rproc) +{ + struct da8xx_rproc *drproc = rproc->priv; + + clk_disable(drproc->dsp_clk); + + return 0; +} + +/* kick a virtqueue */ +static void da8xx_rproc_kick(struct rproc *rproc, int vqid) +{ + struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + + /* Interupt remote proc */ + writel(SYSCFG_CHIPSIG2, drproc->chipsig); +} + +static struct rproc_ops da8xx_rproc_ops = { + .start = da8xx_rproc_start, + .stop = da8xx_rproc_stop, + .kick = da8xx_rproc_kick, +}; + +static int reset_assert(struct device *dev) +{ + struct clk *dsp_clk; + + dsp_clk = clk_get(dev, NULL); + if (IS_ERR(dsp_clk)) { + dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); + return PTR_RET(dsp_clk); + } + + davinci_clk_reset_assert(dsp_clk); + clk_put(dsp_clk); + + return 0; +} + +static int da8xx_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct da8xx_rproc *drproc; + struct rproc *rproc; + struct irq_data *irq_data; + struct resource *bootreg_res; + struct resource *chipsig_res; + struct clk *dsp_clk; + void __iomem *chipsig; + void __iomem *bootreg; + int irq; + int ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "platform_get_irq(pdev, 0) error: %d\n", irq); + return irq; + } + + irq_data = irq_get_irq_data(irq); + if (!irq_data) { + dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq); + return -EINVAL; + } + + bootreg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!bootreg_res) { + dev_err(dev, + "platform_get_resource(IORESOURCE_MEM, 0): NULL\n"); + return -EADDRNOTAVAIL; + } + + chipsig_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!chipsig_res) { + dev_err(dev, + "platform_get_resource(IORESOURCE_MEM, 1): NULL\n"); + return -EADDRNOTAVAIL; + } + + bootreg = devm_ioremap_resource(dev, bootreg_res); + if (IS_ERR(bootreg)) + return PTR_ERR(bootreg); + + chipsig = devm_ioremap_resource(dev, chipsig_res); + if (IS_ERR(chipsig)) + return PTR_ERR(chipsig); + + dsp_clk = devm_clk_get(dev, NULL); + if (IS_ERR(dsp_clk)) { + dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); + + return PTR_ERR(dsp_clk); + } + + rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, + sizeof(*drproc)); + if (!rproc) + return -ENOMEM; + + drproc = rproc->priv; + drproc->rproc = rproc; + + platform_set_drvdata(pdev, rproc); + + /* everything the ISR needs is now setup, so hook it up */ + ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, + handle_event, 0, "da8xx-remoteproc", + rproc); + if (ret) { + dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); + goto free_rproc; + } + + /* + * rproc_add() can end up enabling the DSP's clk with the DSP + * *not* in reset, but da8xx_rproc_start() needs the DSP to be + * held in reset at the time it is called. + */ + ret = reset_assert(dev); + if (ret) + goto free_rproc; + + drproc->chipsig = chipsig; + drproc->bootreg = bootreg; + drproc->ack_fxn = irq_data->chip->irq_ack; + drproc->irq_data = irq_data; + drproc->irq = irq; + drproc->dsp_clk = dsp_clk; + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "rproc_add failed: %d\n", ret); + goto free_rproc; + } + + return 0; + +free_rproc: + rproc_put(rproc); + + return ret; +} + +static int da8xx_rproc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rproc *rproc = platform_get_drvdata(pdev); + struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + + /* + * It's important to place the DSP in reset before going away, + * since a subsequent insmod of this module may enable the DSP's + * clock before its program/boot-address has been loaded and + * before this module's probe has had a chance to reset the DSP. + * Without the reset, the DSP can lockup permanently when it + * begins executing garbage. + */ + reset_assert(dev); + + /* + * The devm subsystem might end up releasing things before + * freeing the irq, thus allowing an interrupt to sneak in while + * the device is being removed. This should prevent that. + */ + disable_irq(drproc->irq); + + devm_clk_put(dev, drproc->dsp_clk); + + rproc_del(rproc); + rproc_put(rproc); + + return 0; +} + +static struct platform_driver da8xx_rproc_driver = { + .probe = da8xx_rproc_probe, + .remove = da8xx_rproc_remove, + .driver = { + .name = "davinci-rproc", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da8xx_rproc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DA8XX Remote Processor control driver"); -- cgit v1.2.3-59-g8ed1b From b9777859ec015a78dae1476e317d04f851bfdd0d Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 21 Apr 2013 16:29:38 +0300 Subject: remoteproc: fix kconfig dependencies for VIRTIO Fix this: warning: (VIRTIO_PCI && VIRTIO_MMIO && REMOTEPROC && RPMSG) selects VIRTIO which has unmet direct dependencies (VIRTUALIZATION) Cc: stable@vger.kernel.org Signed-off-by: Suman Anna [edit commit log] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/remoteproc') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index c3675ae3cc9e..1ceb4867c97a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,7 @@ config REMOTEPROC select CRC32 select FW_CONFIG select VIRTIO + select VIRTUALIZATION config OMAP_REMOTEPROC tristate "OMAP remoteproc support" -- cgit v1.2.3-59-g8ed1b