From c78bc072ac80823a5934574e791325dd6817ec10 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 1 Dec 2018 10:58:38 -0500 Subject: remoteproc: convert to DEFINE_SHOW_ATTRIBUTE Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20181201155838.8619-1-tiny.windzz@gmail.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_debugfs.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index d734cadb16e3..732770e92b99 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -269,17 +269,7 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p) return 0; } -static int rproc_rsc_table_open(struct inode *inode, struct file *file) -{ - return single_open(file, rproc_rsc_table_show, inode->i_private); -} - -static const struct file_operations rproc_rsc_table_ops = { - .open = rproc_rsc_table_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(rproc_rsc_table); /* Expose carveout content via debugfs */ static int rproc_carveouts_show(struct seq_file *seq, void *p) @@ -299,17 +289,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p) return 0; } -static int rproc_carveouts_open(struct inode *inode, struct file *file) -{ - return single_open(file, rproc_carveouts_show, inode->i_private); -} - -static const struct file_operations rproc_carveouts_ops = { - .open = rproc_carveouts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(rproc_carveouts); void rproc_remove_trace_file(struct dentry *tfile) { @@ -354,9 +334,9 @@ void rproc_create_debug_dir(struct rproc *rproc) debugfs_create_file("crash", 0200, rproc->dbg_dir, rproc, &rproc_crash_ops); debugfs_create_file("resource_table", 0400, rproc->dbg_dir, - rproc, &rproc_rsc_table_ops); + rproc, &rproc_rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, - rproc, &rproc_carveouts_ops); + rproc, &rproc_carveouts_fops); } void __init rproc_init_debugfs(void) -- cgit v1.2.3 From 6442df49400b466431979e7634849a464a5f1861 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Apr 2020 14:48:52 -0600 Subject: remoteproc: Fix IDR initialisation in rproc_alloc() If ida_simple_get() returns an error when called in rproc_alloc(), put_device() is called to clean things up. By this time the rproc device type has been assigned, with rproc_type_release() as the release function. The first thing rproc_type_release() does is call: idr_destroy(&rproc->notifyids); But at the time the ida_simple_get() call is made, the notifyids field in the remoteproc structure has not been initialized. I'm not actually sure this case causes an observable problem, but it's incorrect. Fix this by initializing the notifyids field before calling ida_simple_get() in rproc_alloc(). Fixes: b5ab5e24e960 ("remoteproc: maintain a generic child device for each rproc") Signed-off-by: Alex Elder Reviewed-by: Mathieu Poirier Reviewed-by: Suman Anna Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20200415204858.2448-2-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e12a54e67588..80056513ae71 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2053,6 +2053,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->dev.type = &rproc_type; rproc->dev.class = &rproc_class; rproc->dev.driver_data = rproc; + idr_init(&rproc->notifyids); /* Assign a unique device index and name */ rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL); @@ -2078,8 +2079,6 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, mutex_init(&rproc->lock); - idr_init(&rproc->notifyids); - INIT_LIST_HEAD(&rproc->carveouts); INIT_LIST_HEAD(&rproc->mappings); INIT_LIST_HEAD(&rproc->traces); -- cgit v1.2.3 From 0c2ae2b1afdfffa5e485614569d2ff12dee97fc5 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Wed, 15 Apr 2020 14:48:53 -0600 Subject: remoteproc: Split firmware name allocation from rproc_alloc() Make the firmware name allocation a function on its own in an effort to cleanup function rproc_alloc(). Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20200415204858.2448-3-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 66 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 80056513ae71..4dee63f319ba 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1979,6 +1979,33 @@ static const struct device_type rproc_type = { .release = rproc_type_release, }; +static int rproc_alloc_firmware(struct rproc *rproc, + const char *name, const char *firmware) +{ + char *p, *template = "rproc-%s-fw"; + int name_len; + + if (!firmware) { + /* + * If the caller didn't pass in a firmware name then + * construct a default name. + */ + name_len = strlen(name) + strlen(template) - 2 + 1; + p = kmalloc(name_len, GFP_KERNEL); + if (!p) + return -ENOMEM; + snprintf(p, name_len, template, name); + } else { + p = kstrdup(firmware, GFP_KERNEL); + if (!p) + return -ENOMEM; + } + + rproc->firmware = p; + + return 0; +} + /** * rproc_alloc() - allocate a remote processor handle * @dev: the underlying device @@ -2007,42 +2034,21 @@ 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; if (!dev || !name || !ops) return NULL; - if (!firmware) { - /* - * If the caller didn't pass in a firmware name then - * construct a default name. - */ - name_len = strlen(name) + strlen(template) - 2 + 1; - p = kmalloc(name_len, GFP_KERNEL); - if (!p) - return NULL; - snprintf(p, name_len, template, name); - } else { - p = kstrdup(firmware, GFP_KERNEL); - if (!p) - return NULL; - } - rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL); - if (!rproc) { - kfree(p); + if (!rproc) return NULL; - } + + if (rproc_alloc_firmware(rproc, name, firmware)) + goto free_rproc; rproc->ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL); - if (!rproc->ops) { - kfree(p); - kfree(rproc); - return NULL; - } + if (!rproc->ops) + goto free_firmware; - rproc->firmware = p; rproc->name = name; rproc->priv = &rproc[1]; rproc->auto_boot = true; @@ -2091,6 +2097,12 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->state = RPROC_OFFLINE; return rproc; + +free_firmware: + kfree(rproc->firmware); +free_rproc: + kfree(rproc); + return NULL; } EXPORT_SYMBOL(rproc_alloc); -- cgit v1.2.3 From 4df4f8be8b3e9ce807ba47c030893d711abe6ee3 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Wed, 15 Apr 2020 14:48:54 -0600 Subject: remoteproc: Simplify default name allocation In an effort to cleanup firmware name allocation, replace the cumbersome mechanic used to allocate a default firmware name with function kasprintf(). Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Suggested-by: Bjorn Andersson Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20200415204858.2448-4-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4dee63f319ba..9899467fa1cf 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1982,24 +1982,19 @@ static const struct device_type rproc_type = { static int rproc_alloc_firmware(struct rproc *rproc, const char *name, const char *firmware) { - char *p, *template = "rproc-%s-fw"; - int name_len; + char *p; - if (!firmware) { + if (!firmware) /* * If the caller didn't pass in a firmware name then * construct a default name. */ - name_len = strlen(name) + strlen(template) - 2 + 1; - p = kmalloc(name_len, GFP_KERNEL); - if (!p) - return -ENOMEM; - snprintf(p, name_len, template, name); - } else { + p = kasprintf(GFP_KERNEL, "rproc-%s-fw", name); + else p = kstrdup(firmware, GFP_KERNEL); - if (!p) - return -ENOMEM; - } + + if (!p) + return -ENOMEM; rproc->firmware = p; -- cgit v1.2.3 From 418fd78771220f5e522d02676758ed824c349fd5 Mon Sep 17 00:00:00 2001 From: Clement Leger Date: Fri, 10 Apr 2020 12:24:32 +0200 Subject: remoteproc: add rproc_coredump_set_elf_info This function allows drivers to correctly setup the coredump output elf information. Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Signed-off-by: Clement Leger Link: https://lore.kernel.org/r/20200410102433.2672-2-cleger@kalray.eu Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 32 ++++++++++++++++++++++++++++-- drivers/remoteproc/remoteproc_elf_loader.c | 3 --- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9899467fa1cf..d9e6949e4ac1 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1565,6 +1565,28 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, } EXPORT_SYMBOL(rproc_coredump_add_custom_segment); +/** + * rproc_coredump_set_elf_info() - set coredump elf information + * @rproc: handle of a remote processor + * @class: elf class for coredump elf file + * @machine: elf machine for coredump elf file + * + * Set elf information which will be used for coredump elf file. + * + * Return: 0 on success, negative errno on error. + */ +int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) +{ + if (class != ELFCLASS64 && class != ELFCLASS32) + return -EINVAL; + + rproc->elf_class = class; + rproc->elf_machine = machine; + + return 0; +} +EXPORT_SYMBOL(rproc_coredump_set_elf_info); + /** * rproc_coredump() - perform coredump * @rproc: rproc handle @@ -1587,6 +1609,11 @@ static void rproc_coredump(struct rproc *rproc) if (list_empty(&rproc->dump_segments)) return; + if (class == ELFCLASSNONE) { + dev_err(&rproc->dev, "Elf class is not set\n"); + return; + } + data_size = elf_size_of_hdr(class); list_for_each_entry(segment, &rproc->dump_segments, node) { data_size += elf_size_of_phdr(class) + segment->size; @@ -1605,7 +1632,7 @@ static void rproc_coredump(struct rproc *rproc) elf_hdr_init_ident(ehdr, class); elf_hdr_set_e_type(class, ehdr, ET_CORE); - elf_hdr_set_e_machine(class, ehdr, EM_NONE); + elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); elf_hdr_set_e_version(class, ehdr, EV_CURRENT); elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class)); @@ -2047,7 +2074,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->name = name; rproc->priv = &rproc[1]; rproc->auto_boot = true; - rproc->elf_class = ELFCLASS32; + rproc->elf_class = ELFCLASSNONE; + rproc->elf_machine = EM_NONE; device_initialize(&rproc->dev); rproc->dev.parent = dev; diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 16e2c496fd45..4869fb7d8fe4 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -248,9 +248,6 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) memset(ptr + filesz, 0, memsz - filesz); } - if (ret == 0) - rproc->elf_class = class; - return ret; } EXPORT_SYMBOL(rproc_elf_load_segments); -- cgit v1.2.3 From 3898fc99d199346348b3efe1f6657b9eb7fa56cd Mon Sep 17 00:00:00 2001 From: Clement Leger Date: Fri, 10 Apr 2020 12:24:33 +0200 Subject: remoteproc: use rproc_coredump_set_elf_info in drivers Modify drivers which are using remoteproc coredump functionality to use rproc_coredump_set_elf_info in order to create correct elf coredump format. Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Signed-off-by: Clement Leger Link: https://lore.kernel.org/r/20200410102433.2672-3-cleger@kalray.eu Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_adsp.c | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 3 +++ drivers/remoteproc/qcom_q6v5_pas.c | 1 + drivers/remoteproc/qcom_wcnss.c | 1 + drivers/remoteproc/stm32_rproc.c | 1 + 5 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 24a3db961d5e..c60dabc6939e 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -431,6 +431,7 @@ static int adsp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to allocate remoteproc\n"); return -ENOMEM; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); adsp = (struct qcom_adsp *)rproc->priv; adsp->dev = &pdev->dev; diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index ce49c3236ff7..a335d2eebe97 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1357,6 +1357,8 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, return ret; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); qproc->dump_complete_mask = 0; @@ -1667,6 +1669,7 @@ static int q6v5_probe(struct platform_device *pdev) } rproc->auto_boot = false; + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); qproc = (struct q6v5 *)rproc->priv; qproc->dev = &pdev->dev; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 7a63efb85405..8ecc157f1ed1 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -398,6 +398,7 @@ static int adsp_probe(struct platform_device *pdev) } rproc->auto_boot = desc->auto_boot; + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); adsp = (struct qcom_adsp *)rproc->priv; adsp->dev = &pdev->dev; diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 0c7afd038f0d..5d65e1a9329a 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -480,6 +480,7 @@ static int wcnss_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to allocate remoteproc\n"); return -ENOMEM; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); wcnss = (struct qcom_wcnss *)rproc->priv; wcnss->dev = &pdev->dev; diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 6a66dbf2df40..0f9d02ca4f5a 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -625,6 +625,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) if (!rproc) return -ENOMEM; + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); rproc->has_iommu = false; ddata = rproc->priv; ddata->workqueue = create_workqueue(dev_name(dev)); -- cgit v1.2.3 From 66a4347e9a3e6adf9d3d5ceb9856cbed3d805beb Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Wed, 8 Apr 2020 16:36:38 -0700 Subject: remoteproc: sysmon: Add ability to send type of notification Current implementation of the sysmon driver does not support adding notifications for other remoteproc events - prepare, start, unprepare. Clients on the remoteproc side might be interested in knowing when a remoteproc boots up. This change adds the ability to send the notification type along with the name. For example, audio DSP is interested in knowing when modem has crashed so that it can perform cleanup and wait for modem to boot up before it starts processing data again. Acked-by: Mathieu Poirier Reviewed-by: Bjorn Andersson Signed-off-by: Siddharth Gupta Link: https://lore.kernel.org/r/1586389003-26675-2-git-send-email-sidgup@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_sysmon.c | 54 +++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index faf3822d8791..13660506b9b0 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -46,6 +46,25 @@ struct qcom_sysmon { struct sockaddr_qrtr ssctl; }; +enum { + SSCTL_SSR_EVENT_BEFORE_POWERUP, + SSCTL_SSR_EVENT_AFTER_POWERUP, + SSCTL_SSR_EVENT_BEFORE_SHUTDOWN, + SSCTL_SSR_EVENT_AFTER_SHUTDOWN, +}; + +static const char * const sysmon_state_string[] = { + [SSCTL_SSR_EVENT_BEFORE_POWERUP] = "before_powerup", + [SSCTL_SSR_EVENT_AFTER_POWERUP] = "after_powerup", + [SSCTL_SSR_EVENT_BEFORE_SHUTDOWN] = "before_shutdown", + [SSCTL_SSR_EVENT_AFTER_SHUTDOWN] = "after_shutdown", +}; + +struct sysmon_event { + const char *subsys_name; + u32 ssr_event; +}; + static DEFINE_MUTEX(sysmon_lock); static LIST_HEAD(sysmon_list); @@ -54,13 +73,15 @@ static LIST_HEAD(sysmon_list); * @sysmon: sysmon context * @name: other remote's name */ -static void sysmon_send_event(struct qcom_sysmon *sysmon, const char *name) +static void sysmon_send_event(struct qcom_sysmon *sysmon, + const struct sysmon_event *event) { char req[50]; int len; int ret; - len = snprintf(req, sizeof(req), "ssr:%s:before_shutdown", name); + len = snprintf(req, sizeof(req), "ssr:%s:%s", event->subsys_name, + sysmon_state_string[event->ssr_event]); if (len >= sizeof(req)) return; @@ -148,13 +169,6 @@ static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count, #define SSCTL_SUBSYS_NAME_LENGTH 15 -enum { - SSCTL_SSR_EVENT_BEFORE_POWERUP, - SSCTL_SSR_EVENT_AFTER_POWERUP, - SSCTL_SSR_EVENT_BEFORE_SHUTDOWN, - SSCTL_SSR_EVENT_AFTER_SHUTDOWN, -}; - enum { SSCTL_SSR_EVENT_FORCED, SSCTL_SSR_EVENT_GRACEFUL, @@ -331,7 +345,8 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon) * @sysmon: sysmon context * @name: other remote's name */ -static void ssctl_send_event(struct qcom_sysmon *sysmon, const char *name) +static void ssctl_send_event(struct qcom_sysmon *sysmon, + const struct sysmon_event *event) { struct ssctl_subsys_event_resp resp; struct ssctl_subsys_event_req req; @@ -346,9 +361,9 @@ static void ssctl_send_event(struct qcom_sysmon *sysmon, const char *name) } memset(&req, 0, sizeof(req)); - strlcpy(req.subsys_name, name, sizeof(req.subsys_name)); + strlcpy(req.subsys_name, event->subsys_name, sizeof(req.subsys_name)); req.subsys_name_len = strlen(req.subsys_name); - req.event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN; + req.event = event->ssr_event; req.evt_driven_valid = true; req.evt_driven = SSCTL_SSR_EVENT_FORCED; @@ -432,8 +447,12 @@ static int sysmon_start(struct rproc_subdev *subdev) static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); + struct sysmon_event event = { + .subsys_name = sysmon->name, + .ssr_event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN + }; - blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)sysmon->name); + blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); /* Don't request graceful shutdown if we've crashed */ if (crashed) @@ -456,19 +475,20 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event, { struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb); struct rproc *rproc = sysmon->rproc; - const char *ssr_name = data; + struct sysmon_event *sysmon_event = data; /* Skip non-running rprocs and the originating instance */ - if (rproc->state != RPROC_RUNNING || !strcmp(data, sysmon->name)) { + if (rproc->state != RPROC_RUNNING || + !strcmp(sysmon_event->subsys_name, sysmon->name)) { dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name); return NOTIFY_DONE; } /* Only SSCTL version 2 supports SSR events */ if (sysmon->ssctl_version == 2) - ssctl_send_event(sysmon, ssr_name); + ssctl_send_event(sysmon, sysmon_event); else if (sysmon->ept) - sysmon_send_event(sysmon, ssr_name); + sysmon_send_event(sysmon, sysmon_event); return NOTIFY_DONE; } -- cgit v1.2.3 From 1877f54f75ad16549861ae92a708bd04c23f2a72 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Wed, 8 Apr 2020 16:36:39 -0700 Subject: remoteproc: sysmon: Add notifications for events Add notification for other stages of remoteproc boot and shutdown. This includes adding callback functions for the prepare and unprepare events, and fleshing out the callback function for start. Acked-by: Mathieu Poirier Reviewed-by: Bjorn Andersson Signed-off-by: Siddharth Gupta Link: https://lore.kernel.org/r/1586389003-26675-3-git-send-email-sidgup@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_sysmon.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index 13660506b9b0..851664e1aabe 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -439,8 +439,31 @@ static const struct qmi_ops ssctl_ops = { .del_server = ssctl_del_server, }; +static int sysmon_prepare(struct rproc_subdev *subdev) +{ + struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, + subdev); + struct sysmon_event event = { + .subsys_name = sysmon->name, + .ssr_event = SSCTL_SSR_EVENT_BEFORE_POWERUP + }; + + blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); + + return 0; +} + static int sysmon_start(struct rproc_subdev *subdev) { + struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, + subdev); + struct sysmon_event event = { + .subsys_name = sysmon->name, + .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP + }; + + blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); + return 0; } @@ -464,6 +487,18 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) sysmon_request_shutdown(sysmon); } +static void sysmon_unprepare(struct rproc_subdev *subdev) +{ + struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, + subdev); + struct sysmon_event event = { + .subsys_name = sysmon->name, + .ssr_event = SSCTL_SSR_EVENT_AFTER_SHUTDOWN + }; + + blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); +} + /** * sysmon_notify() - notify sysmon target of another's SSR * @nb: notifier_block associated with sysmon instance @@ -563,8 +598,10 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, qmi_add_lookup(&sysmon->qmi, 43, 0, 0); + sysmon->subdev.prepare = sysmon_prepare; sysmon->subdev.start = sysmon_start; sysmon->subdev.stop = sysmon_stop; + sysmon->subdev.unprepare = sysmon_unprepare; rproc_add_subdev(rproc, &sysmon->subdev); -- cgit v1.2.3 From 1f36ab3f6e3b791eadad94f792c874706e153b66 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Wed, 8 Apr 2020 16:36:40 -0700 Subject: remoteproc: sysmon: Inform current rproc about all active rprocs Clients/services running on a remoteproc that booted up might need to be aware of the state of already running remoteprocs. When a remoteproc boots up (fresh or after recovery) it is not aware of the remoteprocs that booted before it, i.e., the system state is incomplete. So to keep track of it we send sysmon on behalf of all 'ONLINE' remoteprocs. Acked-by: Mathieu Poirier Reviewed-by: Bjorn Andersson Signed-off-by: Siddharth Gupta Link: https://lore.kernel.org/r/1586389003-26675-4-git-send-email-sidgup@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_sysmon.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index 851664e1aabe..8d8996d714f0 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -453,10 +453,20 @@ static int sysmon_prepare(struct rproc_subdev *subdev) return 0; } +/** + * sysmon_start() - start callback for the sysmon remoteproc subdevice + * @subdev: instance of the sysmon subdevice + * + * Inform all the listners of sysmon notifications that the rproc associated + * to @subdev has booted up. The rproc that booted up also needs to know + * which rprocs are already up and running, so send start notifications + * on behalf of all the online rprocs. + */ static int sysmon_start(struct rproc_subdev *subdev) { struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); + struct qcom_sysmon *target; struct sysmon_event event = { .subsys_name = sysmon->name, .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP @@ -464,6 +474,21 @@ static int sysmon_start(struct rproc_subdev *subdev) blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); + mutex_lock(&sysmon_lock); + list_for_each_entry(target, &sysmon_list, node) { + if (target == sysmon || + target->rproc->state != RPROC_RUNNING) + continue; + + event.subsys_name = target->name; + + if (sysmon->ssctl_version == 2) + ssctl_send_event(sysmon, &event); + else if (sysmon->ept) + sysmon_send_event(sysmon, &event); + } + mutex_unlock(&sysmon_lock); + return 0; } -- cgit v1.2.3 From 1487deda19c82d30d1867277e89bc2d515b9d2d4 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 20 Apr 2020 17:15:58 -0600 Subject: remoteproc: Use kstrdup_const() rather than kstrdup() For cases where @firmware is declared "const char *", use function kstrdup_const() to avoid needlessly creating another copy on the heap. Suggested-by: Bjorn Andersson Signed-off-by: Mathieu Poirier Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20200420231601.16781-2-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index d9e6949e4ac1..db8a15fc1e4a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1996,7 +1996,7 @@ static void rproc_type_release(struct device *dev) if (rproc->index >= 0) ida_simple_remove(&rproc_dev_index, rproc->index); - kfree(rproc->firmware); + kfree_const(rproc->firmware); kfree(rproc->ops); kfree(rproc); } @@ -2009,7 +2009,7 @@ static const struct device_type rproc_type = { static int rproc_alloc_firmware(struct rproc *rproc, const char *name, const char *firmware) { - char *p; + const char *p; if (!firmware) /* @@ -2018,7 +2018,7 @@ static int rproc_alloc_firmware(struct rproc *rproc, */ p = kasprintf(GFP_KERNEL, "rproc-%s-fw", name); else - p = kstrdup(firmware, GFP_KERNEL); + p = kstrdup_const(firmware, GFP_KERNEL); if (!p) return -ENOMEM; @@ -2122,7 +2122,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, return rproc; free_firmware: - kfree(rproc->firmware); + kfree_const(rproc->firmware); free_rproc: kfree(rproc); return NULL; -- cgit v1.2.3 From 9d5f82c8ba2471e34150a0e750ef54089e2a3740 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 20 Apr 2020 17:15:59 -0600 Subject: remoteproc: Restructure firmware name allocation Improve the readability of function rproc_alloc_firmware() by using a non-negated condition and moving the comment out of the conditional block Suggested-by: Alex Elder Signed-off-by: Mathieu Poirier Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20200420231601.16781-3-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index db8a15fc1e4a..45529d40342f 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2011,14 +2011,14 @@ static int rproc_alloc_firmware(struct rproc *rproc, { const char *p; - if (!firmware) - /* - * If the caller didn't pass in a firmware name then - * construct a default name. - */ - p = kasprintf(GFP_KERNEL, "rproc-%s-fw", name); - else + /* + * Allocate a firmware name if the caller gave us one to work + * with. Otherwise construct a new one using a default pattern. + */ + if (firmware) p = kstrdup_const(firmware, GFP_KERNEL); + else + p = kasprintf(GFP_KERNEL, "rproc-%s-fw", name); if (!p) return -ENOMEM; -- cgit v1.2.3 From bf860aa176d0104cfbaf863acbadf5548f1172c2 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 20 Apr 2020 17:16:00 -0600 Subject: remoteproc: Split rproc_ops allocation from rproc_alloc() Make the rproc_ops allocation a function on its own in an effort to clean up function rproc_alloc(). Signed-off-by: Mathieu Poirier Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20200420231601.16781-4-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 45529d40342f..15318507aedb 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2028,6 +2028,26 @@ static int rproc_alloc_firmware(struct rproc *rproc, return 0; } +static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops) +{ + rproc->ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL); + if (!rproc->ops) + return -ENOMEM; + + if (rproc->ops->load) + return 0; + + /* Default to ELF loader if no load function is specified */ + rproc->ops->load = rproc_elf_load_segments; + rproc->ops->parse_fw = rproc_elf_load_rsc_table; + rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table; + if (!rproc->ops->sanity_check) + rproc->ops->sanity_check = rproc_elf32_sanity_check; + rproc->ops->get_boot_addr = rproc_elf_get_boot_addr; + + return 0; +} + /** * rproc_alloc() - allocate a remote processor handle * @dev: the underlying device @@ -2067,8 +2087,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, if (rproc_alloc_firmware(rproc, name, firmware)) goto free_rproc; - rproc->ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL); - if (!rproc->ops) + if (rproc_alloc_ops(rproc, ops)) goto free_firmware; rproc->name = name; @@ -2096,16 +2115,6 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, atomic_set(&rproc->power, 0); - /* Default to ELF loader if no load function is specified */ - if (!rproc->ops->load) { - rproc->ops->load = rproc_elf_load_segments; - rproc->ops->parse_fw = rproc_elf_load_rsc_table; - rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table; - if (!rproc->ops->sanity_check) - rproc->ops->sanity_check = rproc_elf32_sanity_check; - rproc->ops->get_boot_addr = rproc_elf_get_boot_addr; - } - mutex_init(&rproc->lock); INIT_LIST_HEAD(&rproc->carveouts); -- cgit v1.2.3 From 226f5db4212438cdfe1a94652d74c6c01788a837 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 20 Apr 2020 17:16:01 -0600 Subject: remoteproc: Get rid of tedious error path Get rid of tedious error management by moving firmware and operation allocation after calling device_initialize(). That way we take advantage of the automatic call to rproc_type_release() to cleanup after ourselves when put_device() is called. Signed-off-by: Mathieu Poirier Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Acked-by: Suman Anna Link: https://lore.kernel.org/r/20200420231601.16781-5-mathieu.poirier@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 15318507aedb..6fca4e2c0dd7 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2084,12 +2084,6 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, if (!rproc) return NULL; - if (rproc_alloc_firmware(rproc, name, firmware)) - goto free_rproc; - - if (rproc_alloc_ops(rproc, ops)) - goto free_firmware; - rproc->name = name; rproc->priv = &rproc[1]; rproc->auto_boot = true; @@ -2103,12 +2097,17 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->dev.driver_data = rproc; idr_init(&rproc->notifyids); + if (rproc_alloc_firmware(rproc, name, firmware)) + goto put_device; + + if (rproc_alloc_ops(rproc, ops)) + goto put_device; + /* Assign a unique device index and name */ rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL); if (rproc->index < 0) { dev_err(dev, "ida_simple_get failed: %d\n", rproc->index); - put_device(&rproc->dev); - return NULL; + goto put_device; } dev_set_name(&rproc->dev, "remoteproc%d", rproc->index); @@ -2130,10 +2129,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, return rproc; -free_firmware: - kfree_const(rproc->firmware); -free_rproc: - kfree(rproc); +put_device: + put_device(&rproc->dev); return NULL; } EXPORT_SYMBOL(rproc_alloc); -- cgit v1.2.3 From db65527836156fe9c6abe6b9b4aa02fac49a67e3 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Thu, 16 Apr 2020 19:20:36 -0500 Subject: remoteproc: Use a local copy for the name field The current name field used in the remoteproc structure is simply a pointer to a name field supplied during the rproc_alloc() call. The pointer passed in by remoteproc drivers during registration is typically a dev_name pointer, but it is possible that the pointer will no longer remain valid if the devices themselves were created at runtime like in the case of of_platform_populate(), and were deleted upon any failures within the respective remoteproc driver probe function. So, allocate and maintain a local copy for this name field to keep it agnostic of the logic used in the remoteproc drivers. Reviewed-by: Mathieu Poirier Reviewed-by: Bjorn Andersson Signed-off-by: Suman Anna Link: https://lore.kernel.org/r/20200417002036.24359-3-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 6fca4e2c0dd7..a352362d8e48 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1997,6 +1997,7 @@ static void rproc_type_release(struct device *dev) ida_simple_remove(&rproc_dev_index, rproc->index); kfree_const(rproc->firmware); + kfree_const(rproc->name); kfree(rproc->ops); kfree(rproc); } @@ -2084,7 +2085,6 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, if (!rproc) return NULL; - rproc->name = name; rproc->priv = &rproc[1]; rproc->auto_boot = true; rproc->elf_class = ELFCLASSNONE; @@ -2097,6 +2097,10 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->dev.driver_data = rproc; idr_init(&rproc->notifyids); + rproc->name = kstrdup_const(name, GFP_KERNEL); + if (!rproc->name) + goto put_device; + if (rproc_alloc_firmware(rproc, name, firmware)) goto put_device; -- cgit v1.2.3 From 305ac5a766b1d0dd8a4052c8c92e5464888eaa10 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 17 Apr 2020 19:00:37 +0200 Subject: remoteproc: Add device-managed variants of rproc_alloc/rproc_add Add API functions devm_rproc_alloc() and devm_rproc_add(), which behave like rproc_alloc() and rproc_add() respectively, but register their respective cleanup function to be called on driver detach. Reviewed-by: Bjorn Andersson Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20200417170040.174319-2-paul@crapouillou.net Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index a352362d8e48..448262470fc7 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1976,6 +1976,33 @@ int rproc_add(struct rproc *rproc) } EXPORT_SYMBOL(rproc_add); +static void devm_rproc_remove(void *rproc) +{ + rproc_del(rproc); +} + +/** + * devm_rproc_add() - resource managed rproc_add() + * @dev: the underlying device + * @rproc: the remote processor handle to register + * + * This function performs like rproc_add() but the registered rproc device will + * automatically be removed on driver detach. + * + * Returns: 0 on success, negative errno on failure + */ +int devm_rproc_add(struct device *dev, struct rproc *rproc) +{ + int err; + + err = rproc_add(rproc); + if (err) + return err; + + return devm_add_action_or_reset(dev, devm_rproc_remove, rproc); +} +EXPORT_SYMBOL(devm_rproc_add); + /** * rproc_type_release() - release a remote processor instance * @dev: the rproc's device @@ -2215,6 +2242,46 @@ int rproc_del(struct rproc *rproc) } EXPORT_SYMBOL(rproc_del); +static void devm_rproc_free(struct device *dev, void *res) +{ + rproc_free(*(struct rproc **)res); +} + +/** + * devm_rproc_alloc() - resource managed rproc_alloc() + * @dev: the underlying device + * @name: name of this remote processor + * @ops: platform-specific handlers (mainly start/stop) + * @firmware: name of firmware file to load, can be NULL + * @len: length of private data needed by the rproc driver (in bytes) + * + * This function performs like rproc_alloc() but the acquired rproc device will + * automatically be released on driver detach. + * + * Returns: new rproc instance, or NULL on failure + */ +struct rproc *devm_rproc_alloc(struct device *dev, const char *name, + const struct rproc_ops *ops, + const char *firmware, int len) +{ + struct rproc **ptr, *rproc; + + ptr = devres_alloc(devm_rproc_free, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + rproc = rproc_alloc(dev, name, ops, firmware, len); + if (rproc) { + *ptr = rproc; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return rproc; +} +EXPORT_SYMBOL(devm_rproc_alloc); + /** * rproc_add_subdev() - add a subdevice to a remoteproc * @rproc: rproc handle to add the subdevice to -- cgit v1.2.3 From e29ff72b779426c7fe462ead93c7ad77fe562935 Mon Sep 17 00:00:00 2001 From: Clement Leger Date: Wed, 22 Apr 2020 11:30:17 +0200 Subject: remoteproc: remove rproc_elf32_sanity_check Since checks are present in the remoteproc elf loader before calling da_to_va, loading a elf64 will work on 32bits flavors of kernel. Indeed, if a segment size is larger than what size_t can hold, the loader will return an error so the functionality is equivalent to what exists today. Acked-by: Suman Anna Signed-off-by: Clement Leger Link: https://lore.kernel.org/r/20200422093017.10985-1-cleger@kalray.eu Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 3 +-- drivers/remoteproc/remoteproc_elf_loader.c | 21 --------------------- drivers/remoteproc/remoteproc_internal.h | 1 - drivers/remoteproc/st_remoteproc.c | 2 +- drivers/remoteproc/st_slim_rproc.c | 2 +- drivers/remoteproc/stm32_rproc.c | 2 +- 6 files changed, 4 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 448262470fc7..206363723071 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2069,8 +2069,7 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops) rproc->ops->load = rproc_elf_load_segments; rproc->ops->parse_fw = rproc_elf_load_rsc_table; rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table; - if (!rproc->ops->sanity_check) - rproc->ops->sanity_check = rproc_elf32_sanity_check; + rproc->ops->sanity_check = rproc_elf_sanity_check; rproc->ops->get_boot_addr = rproc_elf_get_boot_addr; return 0; diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 4869fb7d8fe4..df68d87752e4 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -112,27 +112,6 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) } EXPORT_SYMBOL(rproc_elf_sanity_check); -/** - * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image - * @rproc: the remote processor handle - * @fw: the ELF32 firmware image - * - * Make sure this fw image is sane. - */ -int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw) -{ - int ret = rproc_elf_sanity_check(rproc, fw); - - if (ret) - return ret; - - if (fw_elf_get_class(fw) == ELFCLASS32) - return 0; - - return -EINVAL; -} -EXPORT_SYMBOL(rproc_elf32_sanity_check); - /** * rproc_elf_get_boot_addr() - Get rproc's boot address. * @rproc: the remote processor handle diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index b389dc79da81..31994715fd43 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -54,7 +54,6 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len); phys_addr_t rproc_va_to_pa(void *cpu_addr); int rproc_trigger_recovery(struct rproc *rproc); -int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw); int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw); u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw); int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw); diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index a6cbfa452764..a3268d95a50e 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -233,7 +233,7 @@ static const struct rproc_ops st_rproc_ops = { .parse_fw = st_rproc_parse_fw, .load = rproc_elf_load_segments, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, - .sanity_check = rproc_elf32_sanity_check, + .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr, }; diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c index 3cca8b65a8db..09bcb4d8b9e0 100644 --- a/drivers/remoteproc/st_slim_rproc.c +++ b/drivers/remoteproc/st_slim_rproc.c @@ -203,7 +203,7 @@ static const struct rproc_ops slim_rproc_ops = { .da_to_va = slim_rproc_da_to_va, .get_boot_addr = rproc_elf_get_boot_addr, .load = rproc_elf_load_segments, - .sanity_check = rproc_elf32_sanity_check, + .sanity_check = rproc_elf_sanity_check, }; /** diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 0f9d02ca4f5a..f45b8d597da0 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -505,7 +505,7 @@ static struct rproc_ops st_rproc_ops = { .load = rproc_elf_load_segments, .parse_fw = stm32_rproc_parse_fw, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, - .sanity_check = rproc_elf32_sanity_check, + .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr, }; -- cgit v1.2.3 From 33467ac3c8dc80575e1b158e78d0c30ab33c1b08 Mon Sep 17 00:00:00 2001 From: Loic Pallardy Date: Thu, 16 Apr 2020 19:20:35 -0500 Subject: remoteproc: Add prepare and unprepare ops On some SoC architecture, it is needed to enable HW like clock, bus, regulator, memory region... before loading co-processor firmware. This patch introduces prepare and unprepare ops to execute platform specific function before firmware loading and after stop execution. Signed-off-by: Loic Pallardy Signed-off-by: Suman Anna Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20200417002036.24359-2-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 15 ++++++++++++++- drivers/remoteproc/remoteproc_internal.h | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 206363723071..4bd0f45a00c0 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1394,12 +1394,19 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) return ret; } + /* Prepare rproc for firmware loading if needed */ + ret = rproc_prepare_device(rproc); + if (ret) { + dev_err(dev, "can't prepare rproc %s: %d\n", rproc->name, ret); + goto disable_iommu; + } + rproc->bootaddr = rproc_get_boot_addr(rproc, fw); /* Load resource table, core dump segment list etc from the firmware */ ret = rproc_parse_fw(rproc, fw); if (ret) - goto disable_iommu; + goto unprepare_rproc; /* reset max_notifyid */ rproc->max_notifyid = -1; @@ -1433,6 +1440,9 @@ clean_up_resources: kfree(rproc->cached_table); rproc->cached_table = NULL; rproc->table_ptr = NULL; +unprepare_rproc: + /* release HW resources if needed */ + rproc_unprepare_device(rproc); disable_iommu: rproc_disable_iommu(rproc); return ret; @@ -1865,6 +1875,9 @@ void rproc_shutdown(struct rproc *rproc) /* clean up all acquired resources */ rproc_resource_cleanup(rproc); + /* release HW resources if needed */ + rproc_unprepare_device(rproc); + rproc_disable_iommu(rproc); /* Free the copy of the resource table */ diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 31994715fd43..4ba7cb59d3e8 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -63,6 +63,22 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, struct rproc_mem_entry * rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...); +static inline int rproc_prepare_device(struct rproc *rproc) +{ + if (rproc->ops->prepare) + return rproc->ops->prepare(rproc); + + return 0; +} + +static inline int rproc_unprepare_device(struct rproc *rproc) +{ + if (rproc->ops->unprepare) + return rproc->ops->unprepare(rproc); + + return 0; +} + static inline int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) { -- cgit v1.2.3 From 2fb75ceaf71a4a198fc67b984aa95527c993fa1a Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 11 Apr 2020 18:07:50 +0200 Subject: remoteproc: Add missing '\n' in log messages Message logged by 'dev_xxx()' or 'pr_xxx()' should end with a '\n'. Fixes: 791c13b709dd ("remoteproc: Fix NULL pointer dereference in rproc_virtio_notify") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20200411160750.32573-1-christophe.jaillet@wanadoo.fr Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_virtio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index e61d738d9b47..15ec5fc65257 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -337,8 +337,7 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) if (rproc->ops->kick == NULL) { ret = -EINVAL; - dev_err(dev, ".kick method not defined for %s", - rproc->name); + dev_err(dev, ".kick method not defined for %s\n", rproc->name); goto out; } -- cgit v1.2.3 From cd9fc8f1b35bd75e0d33470a01baff2848a9443a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 22 Apr 2020 17:37:33 -0700 Subject: remoteproc: qcom: Pass ssr_name to glink subdevice Pass ssr_name to glink subdevice in preparation for tying glink_ssr to the glink subdevice, rather than having its own "ssr subdevice". Acked-by: Chris Lew Acked-by: Mathieu Poirier Acked-by: Rishabh Bhatnagar Link: https://lore.kernel.org/r/20200423003736.2027371-2-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 9 ++++++++- drivers/remoteproc/qcom_common.h | 5 ++++- drivers/remoteproc/qcom_q6v5_adsp.c | 2 +- drivers/remoteproc/qcom_q6v5_mss.c | 2 +- drivers/remoteproc/qcom_q6v5_pas.c | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 60650bcc8c67..ff26f2b68752 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -46,8 +46,10 @@ static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed) * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc * @rproc: rproc handle to parent the subdevice * @glink: reference to a GLINK subdev context + * @ssr_name: identifier of the associated remoteproc for ssr notifications */ -void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) +void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, + const char *ssr_name) { struct device *dev = &rproc->dev; @@ -55,6 +57,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) if (!glink->node) return; + glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL); + if (!glink->ssr_name) + return; + glink->dev = dev; glink->subdev.start = glink_subdev_start; glink->subdev.stop = glink_subdev_stop; @@ -74,6 +80,7 @@ void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glin return; rproc_remove_subdev(rproc, &glink->subdev); + kfree_const(glink->ssr_name); of_node_put(glink->node); } EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h index 58de71e4781c..34e5188187dc 100644 --- a/drivers/remoteproc/qcom_common.h +++ b/drivers/remoteproc/qcom_common.h @@ -11,6 +11,8 @@ struct qcom_sysmon; struct qcom_rproc_glink { struct rproc_subdev subdev; + const char *ssr_name; + struct device *dev; struct device_node *node; struct qcom_glink *edge; @@ -30,7 +32,8 @@ struct qcom_rproc_ssr { const char *name; }; -void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink); +void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, + const char *ssr_name); void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink); int qcom_register_dump_segments(struct rproc *rproc, const struct firmware *fw); diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index c60dabc6939e..d2a2574dcf35 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -461,7 +461,7 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto disable_pm; - qcom_add_glink_subdev(rproc, &adsp->glink_subdev); + qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name); qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name); adsp->sysmon = qcom_add_sysmon_subdev(rproc, desc->sysmon_name, diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index a335d2eebe97..38d2b21735da 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1762,7 +1762,7 @@ static int q6v5_probe(struct platform_device *pdev) qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS); qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); - qcom_add_glink_subdev(rproc, &qproc->glink_subdev); + qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss"); qcom_add_smd_subdev(rproc, &qproc->smd_subdev); qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); qcom_add_ipa_notify_subdev(rproc, &qproc->ipa_notify_subdev); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 8ecc157f1ed1..fc6658b523b6 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -436,7 +436,7 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto detach_proxy_pds; - qcom_add_glink_subdev(rproc, &adsp->glink_subdev); + qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name); qcom_add_smd_subdev(rproc, &adsp->smd_subdev); qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name); adsp->sysmon = qcom_add_sysmon_subdev(rproc, -- cgit v1.2.3 From 5d1f2e3c8090c0769ee4a1b920e82277613327fc Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 22 Apr 2020 17:37:34 -0700 Subject: soc: qcom: glink_ssr: Internalize ssr_notifiers Rather than carrying a special purpose blocking notifier for glink_ssr in remoteproc's qcom_common.c, move it into glink_ssr so allow wider reuse of the common one. The rpmsg glink header file is used in preparation for the next patch. Acked-by: Chris Lew Acked-by: Rishabh Bhatnagar Link: https://lore.kernel.org/r/20200423003736.2027371-3-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 8 ++++++++ drivers/soc/qcom/glink_ssr.c | 24 +++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index ff26f2b68752..9028cea2d81e 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -42,6 +42,13 @@ static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed) glink->edge = NULL; } +static void glink_subdev_unprepare(struct rproc_subdev *subdev) +{ + struct qcom_rproc_glink *glink = to_glink_subdev(subdev); + + qcom_glink_ssr_notify(glink->ssr_name); +} + /** * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc * @rproc: rproc handle to parent the subdevice @@ -64,6 +71,7 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, glink->dev = dev; glink->subdev.start = glink_subdev_start; glink->subdev.stop = glink_subdev_stop; + glink->subdev.unprepare = glink_subdev_unprepare; rproc_add_subdev(rproc, &glink->subdev); } diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c index d7babe3d67bc..847d79c935f1 100644 --- a/drivers/soc/qcom/glink_ssr.c +++ b/drivers/soc/qcom/glink_ssr.c @@ -54,6 +54,19 @@ struct glink_ssr { struct completion completion; }; +/* Notifier list for all registered glink_ssr instances */ +static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); + +/** + * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc + * @ssr_name: name of the remoteproc that has been stopped + */ +void qcom_glink_ssr_notify(const char *ssr_name) +{ + blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name); +} +EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify); + static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 addr) { @@ -81,8 +94,9 @@ static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev, return 0; } -static int qcom_glink_ssr_notify(struct notifier_block *nb, unsigned long event, - void *data) +static int qcom_glink_ssr_notifier_call(struct notifier_block *nb, + unsigned long event, + void *data) { struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb); struct do_cleanup_msg msg; @@ -121,18 +135,18 @@ static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev) ssr->dev = &rpdev->dev; ssr->ept = rpdev->ept; - ssr->nb.notifier_call = qcom_glink_ssr_notify; + ssr->nb.notifier_call = qcom_glink_ssr_notifier_call; dev_set_drvdata(&rpdev->dev, ssr); - return qcom_register_ssr_notifier(&ssr->nb); + return blocking_notifier_chain_register(&ssr_notifiers, &ssr->nb); } static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev) { struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); - qcom_unregister_ssr_notifier(&ssr->nb); + blocking_notifier_chain_unregister(&ssr_notifiers, &ssr->nb); } static const struct rpmsg_device_id qcom_glink_ssr_match[] = { -- cgit v1.2.3 From 93bc3feee8bd5fbe29ad27779c5e7b369fd7c80b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 22 Apr 2020 17:37:35 -0700 Subject: rpmsg: glink: Integrate glink_ssr in qcom_glink In all but the very special case of a system with _only_ glink_rpm, GLINK is dependent on glink_ssr, so move it to rpmsg and combine it with qcom_glink_native in the new qcom_glink kernel module. Acked-by: Chris Lew Acked-by: Rishabh Bhatnagar Link: https://lore.kernel.org/r/20200423003736.2027371-4-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/rpmsg/Kconfig | 6 +- drivers/rpmsg/Makefile | 3 +- drivers/rpmsg/qcom_glink_ssr.c | 166 ++++++++++++++++++++++++++++++++++++++++ drivers/soc/qcom/Kconfig | 9 --- drivers/soc/qcom/Makefile | 1 - drivers/soc/qcom/glink_ssr.c | 170 ----------------------------------------- 6 files changed, 171 insertions(+), 184 deletions(-) create mode 100644 drivers/rpmsg/qcom_glink_ssr.c delete mode 100644 drivers/soc/qcom/glink_ssr.c (limited to 'drivers') diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index a9108ff563dc..f96716893c2a 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -24,13 +24,13 @@ config RPMSG_MTK_SCP remote processors in MediaTek platforms. This use IPI and IPC to communicate with remote processors. -config RPMSG_QCOM_GLINK_NATIVE +config RPMSG_QCOM_GLINK tristate select RPMSG config RPMSG_QCOM_GLINK_RPM tristate "Qualcomm RPM Glink driver" - select RPMSG_QCOM_GLINK_NATIVE + select RPMSG_QCOM_GLINK depends on HAS_IOMEM depends on MAILBOX help @@ -40,7 +40,7 @@ config RPMSG_QCOM_GLINK_RPM config RPMSG_QCOM_GLINK_SMEM tristate "Qualcomm SMEM Glink driver" - select RPMSG_QCOM_GLINK_NATIVE + select RPMSG_QCOM_GLINK depends on MAILBOX depends on QCOM_SMEM help diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index ae92a7fb08f6..ffe932ef6050 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -2,8 +2,9 @@ obj-$(CONFIG_RPMSG) += rpmsg_core.o obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o +qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o +obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o -obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/qcom_glink_ssr.c b/drivers/rpmsg/qcom_glink_ssr.c new file mode 100644 index 000000000000..dcd1ce616974 --- /dev/null +++ b/drivers/rpmsg/qcom_glink_ssr.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, Linaro Ltd. + */ + +#include +#include +#include +#include +#include + +/** + * struct do_cleanup_msg - The data structure for an SSR do_cleanup message + * version: The G-Link SSR protocol version + * command: The G-Link SSR command - do_cleanup + * seq_num: Sequence number + * name_len: Length of the name of the subsystem being restarted + * name: G-Link edge name of the subsystem being restarted + */ +struct do_cleanup_msg { + __le32 version; + __le32 command; + __le32 seq_num; + __le32 name_len; + char name[32]; +}; + +/** + * struct cleanup_done_msg - The data structure for an SSR cleanup_done message + * version: The G-Link SSR protocol version + * response: The G-Link SSR response to a do_cleanup command, cleanup_done + * seq_num: Sequence number + */ +struct cleanup_done_msg { + __le32 version; + __le32 response; + __le32 seq_num; +}; + +/** + * G-Link SSR protocol commands + */ +#define GLINK_SSR_DO_CLEANUP 0 +#define GLINK_SSR_CLEANUP_DONE 1 + +struct glink_ssr { + struct device *dev; + struct rpmsg_endpoint *ept; + + struct notifier_block nb; + + u32 seq_num; + struct completion completion; +}; + +/* Notifier list for all registered glink_ssr instances */ +static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); + +/** + * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc + * @ssr_name: name of the remoteproc that has been stopped + */ +void qcom_glink_ssr_notify(const char *ssr_name) +{ + blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name); +} +EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify); + +static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 addr) +{ + struct cleanup_done_msg *msg = data; + struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); + + if (len < sizeof(*msg)) { + dev_err(ssr->dev, "message too short\n"); + return -EINVAL; + } + + if (le32_to_cpu(msg->version) != 0) + return -EINVAL; + + if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE) + return 0; + + if (le32_to_cpu(msg->seq_num) != ssr->seq_num) { + dev_err(ssr->dev, "invalid sequence number of response\n"); + return -EINVAL; + } + + complete(&ssr->completion); + + return 0; +} + +static int qcom_glink_ssr_notifier_call(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb); + struct do_cleanup_msg msg; + char *ssr_name = data; + int ret; + + ssr->seq_num++; + reinit_completion(&ssr->completion); + + memset(&msg, 0, sizeof(msg)); + msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP); + msg.seq_num = cpu_to_le32(ssr->seq_num); + msg.name_len = cpu_to_le32(strlen(ssr_name)); + strlcpy(msg.name, ssr_name, sizeof(msg.name)); + + ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); + if (ret < 0) + dev_err(ssr->dev, "failed to send cleanup message\n"); + + ret = wait_for_completion_timeout(&ssr->completion, HZ); + if (!ret) + dev_err(ssr->dev, "timeout waiting for cleanup done message\n"); + + return NOTIFY_DONE; +} + +static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev) +{ + struct glink_ssr *ssr; + + ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL); + if (!ssr) + return -ENOMEM; + + init_completion(&ssr->completion); + + ssr->dev = &rpdev->dev; + ssr->ept = rpdev->ept; + ssr->nb.notifier_call = qcom_glink_ssr_notifier_call; + + dev_set_drvdata(&rpdev->dev, ssr); + + return blocking_notifier_chain_register(&ssr_notifiers, &ssr->nb); +} + +static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev) +{ + struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); + + blocking_notifier_chain_unregister(&ssr_notifiers, &ssr->nb); +} + +static const struct rpmsg_device_id qcom_glink_ssr_match[] = { + { "glink_ssr" }, + {} +}; + +static struct rpmsg_driver qcom_glink_ssr_driver = { + .probe = qcom_glink_ssr_probe, + .remove = qcom_glink_ssr_remove, + .callback = qcom_glink_ssr_callback, + .id_table = qcom_glink_ssr_match, + .drv = { + .name = "qcom_glink_ssr", + }, +}; +module_rpmsg_driver(qcom_glink_ssr_driver); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index bf42a17a45de..811c91289cbf 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -35,15 +35,6 @@ config QCOM_GENI_SE driver is also used to manage the common aspects of multiple Serial Engines present in the QUP. -config QCOM_GLINK_SSR - tristate "Qualcomm Glink SSR driver" - depends on RPMSG - depends on QCOM_RPROC_COMMON - help - Say y here to enable GLINK SSR support. The GLINK SSR driver - implements the SSR protocol for notifying the remote processor about - neighboring subsystems going up or down. - config QCOM_GSBI tristate "QCOM General Serial Bus Interface" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 5d6b83dc58e8..e9cacc9ad401 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -3,7 +3,6 @@ CFLAGS_rpmh-rsc.o := -I$(src) obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_OCMEM) += ocmem.o diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c deleted file mode 100644 index 847d79c935f1..000000000000 --- a/drivers/soc/qcom/glink_ssr.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * Copyright (c) 2017, Linaro Ltd. - */ - -#include -#include -#include -#include -#include - -/** - * struct do_cleanup_msg - The data structure for an SSR do_cleanup message - * version: The G-Link SSR protocol version - * command: The G-Link SSR command - do_cleanup - * seq_num: Sequence number - * name_len: Length of the name of the subsystem being restarted - * name: G-Link edge name of the subsystem being restarted - */ -struct do_cleanup_msg { - __le32 version; - __le32 command; - __le32 seq_num; - __le32 name_len; - char name[32]; -}; - -/** - * struct cleanup_done_msg - The data structure for an SSR cleanup_done message - * version: The G-Link SSR protocol version - * response: The G-Link SSR response to a do_cleanup command, cleanup_done - * seq_num: Sequence number - */ -struct cleanup_done_msg { - __le32 version; - __le32 response; - __le32 seq_num; -}; - -/** - * G-Link SSR protocol commands - */ -#define GLINK_SSR_DO_CLEANUP 0 -#define GLINK_SSR_CLEANUP_DONE 1 - -struct glink_ssr { - struct device *dev; - struct rpmsg_endpoint *ept; - - struct notifier_block nb; - - u32 seq_num; - struct completion completion; -}; - -/* Notifier list for all registered glink_ssr instances */ -static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); - -/** - * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc - * @ssr_name: name of the remoteproc that has been stopped - */ -void qcom_glink_ssr_notify(const char *ssr_name) -{ - blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name); -} -EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify); - -static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev, - void *data, int len, void *priv, u32 addr) -{ - struct cleanup_done_msg *msg = data; - struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); - - if (len < sizeof(*msg)) { - dev_err(ssr->dev, "message too short\n"); - return -EINVAL; - } - - if (le32_to_cpu(msg->version) != 0) - return -EINVAL; - - if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE) - return 0; - - if (le32_to_cpu(msg->seq_num) != ssr->seq_num) { - dev_err(ssr->dev, "invalid sequence number of response\n"); - return -EINVAL; - } - - complete(&ssr->completion); - - return 0; -} - -static int qcom_glink_ssr_notifier_call(struct notifier_block *nb, - unsigned long event, - void *data) -{ - struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb); - struct do_cleanup_msg msg; - char *ssr_name = data; - int ret; - - ssr->seq_num++; - reinit_completion(&ssr->completion); - - memset(&msg, 0, sizeof(msg)); - msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP); - msg.seq_num = cpu_to_le32(ssr->seq_num); - msg.name_len = cpu_to_le32(strlen(ssr_name)); - strlcpy(msg.name, ssr_name, sizeof(msg.name)); - - ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); - if (ret < 0) - dev_err(ssr->dev, "failed to send cleanup message\n"); - - ret = wait_for_completion_timeout(&ssr->completion, HZ); - if (!ret) - dev_err(ssr->dev, "timeout waiting for cleanup done message\n"); - - return NOTIFY_DONE; -} - -static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev) -{ - struct glink_ssr *ssr; - - ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL); - if (!ssr) - return -ENOMEM; - - init_completion(&ssr->completion); - - ssr->dev = &rpdev->dev; - ssr->ept = rpdev->ept; - ssr->nb.notifier_call = qcom_glink_ssr_notifier_call; - - dev_set_drvdata(&rpdev->dev, ssr); - - return blocking_notifier_chain_register(&ssr_notifiers, &ssr->nb); -} - -static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev) -{ - struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); - - blocking_notifier_chain_unregister(&ssr_notifiers, &ssr->nb); -} - -static const struct rpmsg_device_id qcom_glink_ssr_match[] = { - { "glink_ssr" }, - {} -}; - -static struct rpmsg_driver qcom_glink_ssr_driver = { - .probe = qcom_glink_ssr_probe, - .remove = qcom_glink_ssr_remove, - .callback = qcom_glink_ssr_callback, - .id_table = qcom_glink_ssr_match, - .drv = { - .name = "qcom_glink_ssr", - }, -}; -module_rpmsg_driver(qcom_glink_ssr_driver); - -MODULE_ALIAS("rpmsg:glink_ssr"); -MODULE_DESCRIPTION("Qualcomm GLINK SSR notifier"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8096f80a5c09b716be207eb042c4e40d6cdefbd2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 9 May 2020 08:42:37 +0000 Subject: remoteproc/mediatek: fix invalid use of sizeof in scp_ipi_init() sizeof() when applied to a pointer typed expression gives the size of the pointer, not that of the pointed data. Reviewed-by: Mathieu Poirier Fixes: 63c13d61eafe ("remoteproc/mediatek: add SCP support for mt8183") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20200509084237.36293-1-weiyongjun1@huawei.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/mtk_scp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index ea3743e7e794..1ebad7084c47 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -132,8 +132,8 @@ static int scp_ipi_init(struct mtk_scp *scp) (struct mtk_share_obj __iomem *)(scp->sram_base + recv_offset); scp->send_buf = (struct mtk_share_obj __iomem *)(scp->sram_base + send_offset); - memset_io(scp->recv_buf, 0, sizeof(scp->recv_buf)); - memset_io(scp->send_buf, 0, sizeof(scp->send_buf)); + memset_io(scp->recv_buf, 0, sizeof(*scp->recv_buf)); + memset_io(scp->send_buf, 0, sizeof(*scp->send_buf)); return 0; } -- cgit v1.2.3 From 620d70b04d43b8659b099b125626325333bc887f Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Tue, 21 Apr 2020 20:02:23 +0530 Subject: remoteproc: qcom: pas: Add SC7180 Modem support Add support for booting the Modem DSP found on Qualcomm's SC7180 SoCs. Tested-by: Evan Green Reviewed-by: Bjorn Andersson Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20200421143228.8981-3-sibis@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index fc6658b523b6..5a33318e8c68 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -638,6 +638,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init }, { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, + { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init}, { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, -- cgit v1.2.3 From 6663ce6facf93727a3a08c5a6408405cd6094c48 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Tue, 21 Apr 2020 20:02:25 +0530 Subject: remoteproc: qcom_q6v5_mss: Extract mba/mpss from memory-region In the absence of mba and mpss sub-child extract the mba/mpss regions from the memory-region property. Tested-by: Evan Green Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20200421143228.8981-5-sibis@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 38d2b21735da..3a7fcd6485eb 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1568,8 +1568,17 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) struct resource r; int ret; + /* + * In the absence of mba/mpss sub-child, extract the mba and mpss + * reserved memory regions from device's memory-region property. + */ child = of_get_child_by_name(qproc->dev->of_node, "mba"); - node = of_parse_phandle(child, "memory-region", 0); + if (!child) + node = of_parse_phandle(qproc->dev->of_node, + "memory-region", 0); + else + node = of_parse_phandle(child, "memory-region", 0); + ret = of_address_to_resource(node, 0, &r); if (ret) { dev_err(qproc->dev, "unable to resolve mba region\n"); @@ -1586,8 +1595,14 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) return -EBUSY; } - child = of_get_child_by_name(qproc->dev->of_node, "mpss"); - node = of_parse_phandle(child, "memory-region", 0); + if (!child) { + node = of_parse_phandle(qproc->dev->of_node, + "memory-region", 1); + } else { + child = of_get_child_by_name(qproc->dev->of_node, "mpss"); + node = of_parse_phandle(child, "memory-region", 0); + } + ret = of_address_to_resource(node, 0, &r); if (ret) { dev_err(qproc->dev, "unable to resolve mpss region\n"); -- cgit v1.2.3 From f6da4831c55ae0c86c496e330f3b61ccbee1fcce Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Apr 2020 11:00:51 -0700 Subject: remoteproc: qcom: pas: Add SM8250 PAS remoteprocs Add audio, compute and sensor DSP compatibles to the Qualcomm PAS binding and driver. Reviewed-by: Sibi Sankar Link: https://lore.kernel.org/r/20200430180051.3795305-2-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 5a33318e8c68..3bb69f58e086 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -508,6 +508,26 @@ static const struct adsp_data sm8150_adsp_resource = { .ssctl_id = 0x14, }; +static const struct adsp_data sm8250_adsp_resource = { + .crash_reason_smem = 423, + .firmware_name = "adsp.mdt", + .pas_id = 1, + .has_aggre2_clk = false, + .auto_boot = true, + .active_pd_names = (char*[]){ + "load_state", + NULL + }, + .proxy_pd_names = (char*[]){ + "lcx", + "lmx", + NULL + }, + .ssr_name = "lpass", + .sysmon_name = "adsp", + .ssctl_id = 0x14, +}; + static const struct adsp_data msm8998_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", @@ -553,6 +573,25 @@ static const struct adsp_data sm8150_cdsp_resource = { .ssctl_id = 0x17, }; +static const struct adsp_data sm8250_cdsp_resource = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mdt", + .pas_id = 18, + .has_aggre2_clk = false, + .auto_boot = true, + .active_pd_names = (char*[]){ + "load_state", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, +}; + static const struct adsp_data mpss_resource_init = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", @@ -604,6 +643,26 @@ static const struct adsp_data sm8150_slpi_resource = { .ssctl_id = 0x16, }; +static const struct adsp_data sm8250_slpi_resource = { + .crash_reason_smem = 424, + .firmware_name = "slpi.mdt", + .pas_id = 12, + .has_aggre2_clk = false, + .auto_boot = true, + .active_pd_names = (char*[]){ + "load_state", + NULL + }, + .proxy_pd_names = (char*[]){ + "lcx", + "lmx", + NULL + }, + .ssr_name = "dsps", + .sysmon_name = "slpi", + .ssctl_id = 0x16, +}; + static const struct adsp_data msm8998_slpi_resource = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", @@ -645,6 +704,9 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sm8150-slpi-pas", .data = &sm8150_slpi_resource}, + { .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource}, + { .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource}, + { .compatible = "qcom,sm8250-slpi-pas", .data = &sm8250_slpi_resource}, { }, }; MODULE_DEVICE_TABLE(of, adsp_of_match); -- cgit v1.2.3 From a9fdc79d488623d36341f0f3d08f5aa1bedb9d53 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 15 Apr 2020 20:21:10 +0530 Subject: remoteproc: qcom_q6v5_mss: Drop accesses to MPSS PERPH register space 7C retail devices using MSA based boot will result in a fuse combination which will prevent accesses to MSS PERPH register space where the mpss clocks and halt-nav reside. So drop all accesses to the MPSS PERPH register space. Issuing HALT NAV request and turning on the mss clocks as part of SSR will no longer be required since the modem firmware will have the necessary fixes to ensure that there are no pending NAV DMA transactions. Tested-by: Evan Green Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20200415145110.20624-3-sibis@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 102 +++++++------------------------------ 1 file changed, 18 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 3a7fcd6485eb..1ded14253a83 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -69,13 +69,9 @@ #define AXI_HALTREQ_REG 0x0 #define AXI_HALTACK_REG 0x4 #define AXI_IDLE_REG 0x8 -#define NAV_AXI_HALTREQ_BIT BIT(0) -#define NAV_AXI_HALTACK_BIT BIT(1) -#define NAV_AXI_IDLE_BIT BIT(2) #define AXI_GATING_VALID_OVERRIDE BIT(0) #define HALT_ACK_TIMEOUT_US 100000 -#define NAV_HALT_ACK_TIMEOUT_US 200 /* QDSP6SS_RESET */ #define Q6SS_STOP_CORE BIT(0) @@ -143,7 +139,7 @@ struct rproc_hexagon_res { int version; bool need_mem_protection; bool has_alt_reset; - bool has_halt_nav; + bool has_spare_reg; }; struct q6v5 { @@ -154,13 +150,11 @@ struct q6v5 { void __iomem *rmb_base; struct regmap *halt_map; - struct regmap *halt_nav_map; struct regmap *conn_map; u32 halt_q6; u32 halt_modem; u32 halt_nc; - u32 halt_nav; u32 conn_box; struct reset_control *mss_restart; @@ -206,7 +200,7 @@ struct q6v5 { struct qcom_sysmon *sysmon; bool need_mem_protection; bool has_alt_reset; - bool has_halt_nav; + bool has_spare_reg; int mpss_perm; int mba_perm; const char *hexagon_mdt_image; @@ -427,21 +421,19 @@ static int q6v5_reset_assert(struct q6v5 *qproc) reset_control_assert(qproc->pdc_reset); ret = reset_control_reset(qproc->mss_restart); reset_control_deassert(qproc->pdc_reset); - } else if (qproc->has_halt_nav) { + } else if (qproc->has_spare_reg) { /* * When the AXI pipeline is being reset with the Q6 modem partly * operational there is possibility of AXI valid signal to * glitch, leading to spurious transactions and Q6 hangs. A work * around is employed by asserting the AXI_GATING_VALID_OVERRIDE - * BIT before triggering Q6 MSS reset. Both the HALTREQ and - * AXI_GATING_VALID_OVERRIDE are withdrawn post MSS assert - * followed by a MSS deassert, while holding the PDC reset. + * BIT before triggering Q6 MSS reset. AXI_GATING_VALID_OVERRIDE + * is withdrawn post MSS assert followed by a MSS deassert, + * while holding the PDC reset. */ reset_control_assert(qproc->pdc_reset); regmap_update_bits(qproc->conn_map, qproc->conn_box, AXI_GATING_VALID_OVERRIDE, 1); - regmap_update_bits(qproc->halt_nav_map, qproc->halt_nav, - NAV_AXI_HALTREQ_BIT, 0); reset_control_assert(qproc->mss_restart); reset_control_deassert(qproc->pdc_reset); regmap_update_bits(qproc->conn_map, qproc->conn_box, @@ -464,7 +456,7 @@ static int q6v5_reset_deassert(struct q6v5 *qproc) ret = reset_control_reset(qproc->mss_restart); writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET); reset_control_deassert(qproc->pdc_reset); - } else if (qproc->has_halt_nav) { + } else if (qproc->has_spare_reg) { ret = reset_control_reset(qproc->mss_restart); } else { ret = reset_control_deassert(qproc->mss_restart); @@ -761,32 +753,6 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc, regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0); } -static void q6v5proc_halt_nav_axi_port(struct q6v5 *qproc, - struct regmap *halt_map, - u32 offset) -{ - unsigned int val; - int ret; - - /* Check if we're already idle */ - ret = regmap_read(halt_map, offset, &val); - if (!ret && (val & NAV_AXI_IDLE_BIT)) - return; - - /* Assert halt request */ - regmap_update_bits(halt_map, offset, NAV_AXI_HALTREQ_BIT, - NAV_AXI_HALTREQ_BIT); - - /* Wait for halt ack*/ - regmap_read_poll_timeout(halt_map, offset, val, - (val & NAV_AXI_HALTACK_BIT), - 5, NAV_HALT_ACK_TIMEOUT_US); - - ret = regmap_read(halt_map, offset, &val); - if (ret || !(val & NAV_AXI_IDLE_BIT)) - dev_err(qproc->dev, "port failed halt\n"); -} - static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) { unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; @@ -951,9 +917,6 @@ static int q6v5_mba_load(struct q6v5 *qproc) halt_axi_ports: q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); - if (qproc->has_halt_nav) - q6v5proc_halt_nav_axi_port(qproc, qproc->halt_nav_map, - qproc->halt_nav); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); reclaim_mba: @@ -1001,9 +964,6 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); - if (qproc->has_halt_nav) - q6v5proc_halt_nav_axi_port(qproc, qproc->halt_nav_map, - qproc->halt_nav); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); if (qproc->version == MSS_MSM8996) { /* @@ -1434,36 +1394,12 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) qproc->halt_modem = args.args[1]; qproc->halt_nc = args.args[2]; - if (qproc->has_halt_nav) { - struct platform_device *nav_pdev; - + if (qproc->has_spare_reg) { ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "qcom,halt-nav-regs", + "qcom,spare-regs", 1, 0, &args); if (ret < 0) { - dev_err(&pdev->dev, "failed to parse halt-nav-regs\n"); - return -EINVAL; - } - - nav_pdev = of_find_device_by_node(args.np); - of_node_put(args.np); - if (!nav_pdev) { - dev_err(&pdev->dev, "failed to get mss clock device\n"); - return -EPROBE_DEFER; - } - - qproc->halt_nav_map = dev_get_regmap(&nav_pdev->dev, NULL); - if (!qproc->halt_nav_map) { - dev_err(&pdev->dev, "failed to get map from device\n"); - return -EINVAL; - } - qproc->halt_nav = args.args[0]; - - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "qcom,halt-nav-regs", - 1, 1, &args); - if (ret < 0) { - dev_err(&pdev->dev, "failed to parse halt-nav-regs\n"); + dev_err(&pdev->dev, "failed to parse spare-regs\n"); return -EINVAL; } @@ -1549,7 +1485,7 @@ static int q6v5_init_reset(struct q6v5 *qproc) return PTR_ERR(qproc->mss_restart); } - if (qproc->has_alt_reset || qproc->has_halt_nav) { + if (qproc->has_alt_reset || qproc->has_spare_reg) { qproc->pdc_reset = devm_reset_control_get_exclusive(qproc->dev, "pdc_reset"); if (IS_ERR(qproc->pdc_reset)) { @@ -1697,7 +1633,7 @@ static int q6v5_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qproc); - qproc->has_halt_nav = desc->has_halt_nav; + qproc->has_spare_reg = desc->has_spare_reg; ret = q6v5_init_mem(qproc, pdev); if (ret) goto free_rproc; @@ -1839,8 +1775,6 @@ static const struct rproc_hexagon_res sc7180_mss = { .active_clk_names = (char*[]){ "mnoc_axi", "nav", - "mss_nav", - "mss_crypto", NULL }, .active_pd_names = (char*[]){ @@ -1855,7 +1789,7 @@ static const struct rproc_hexagon_res sc7180_mss = { }, .need_mem_protection = true, .has_alt_reset = false, - .has_halt_nav = true, + .has_spare_reg = true, .version = MSS_SC7180, }; @@ -1890,7 +1824,7 @@ static const struct rproc_hexagon_res sdm845_mss = { }, .need_mem_protection = true, .has_alt_reset = true, - .has_halt_nav = false, + .has_spare_reg = false, .version = MSS_SDM845, }; @@ -1917,7 +1851,7 @@ static const struct rproc_hexagon_res msm8998_mss = { }, .need_mem_protection = true, .has_alt_reset = false, - .has_halt_nav = false, + .has_spare_reg = false, .version = MSS_MSM8998, }; @@ -1947,7 +1881,7 @@ static const struct rproc_hexagon_res msm8996_mss = { }, .need_mem_protection = true, .has_alt_reset = false, - .has_halt_nav = false, + .has_spare_reg = false, .version = MSS_MSM8996, }; @@ -1980,7 +1914,7 @@ static const struct rproc_hexagon_res msm8916_mss = { }, .need_mem_protection = false, .has_alt_reset = false, - .has_halt_nav = false, + .has_spare_reg = false, .version = MSS_MSM8916, }; @@ -2021,7 +1955,7 @@ static const struct rproc_hexagon_res msm8974_mss = { }, .need_mem_protection = false, .has_alt_reset = false, - .has_halt_nav = false, + .has_spare_reg = false, .version = MSS_MSM8974, }; -- cgit v1.2.3 From be050a3429f46ecf13eb2b80f299479f8bb823fb Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 15 Apr 2020 12:46:18 +0530 Subject: remoteproc: qcom_q6v5_mss: map/unmap mpss segments before/after use The application processor accessing the mpss region when the Q6 modem is running will lead to an XPU violation. Fix this by un-mapping the mpss segments post copy during mpss authentication and coredumps. Tested-by: Evan Green Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20200415071619.6052-1-sibis@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 1ded14253a83..30652b381c2c 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1116,7 +1116,13 @@ static int q6v5_mpss_load(struct q6v5 *qproc) goto release_firmware; } - ptr = qproc->mpss_region + offset; + ptr = ioremap_wc(qproc->mpss_phys + offset, phdr->p_memsz); + if (!ptr) { + dev_err(qproc->dev, + "unable to map memory region: %pa+%zx-%x\n", + &qproc->mpss_phys, offset, phdr->p_memsz); + goto release_firmware; + } if (phdr->p_filesz && phdr->p_offset < fw->size) { /* Firmware is large enough to be non-split */ @@ -1125,6 +1131,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) "failed to load segment %d from truncated file %s\n", i, fw_name); ret = -EINVAL; + iounmap(ptr); goto release_firmware; } @@ -1135,6 +1142,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) ret = request_firmware(&seg_fw, fw_name, qproc->dev); if (ret) { dev_err(qproc->dev, "failed to load %s\n", fw_name); + iounmap(ptr); goto release_firmware; } @@ -1147,6 +1155,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); } + iounmap(ptr); size += phdr->p_memsz; code_length = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); @@ -1196,7 +1205,8 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, int ret = 0; struct q6v5 *qproc = rproc->priv; unsigned long mask = BIT((unsigned long)segment->priv); - void *ptr = rproc_da_to_va(rproc, segment->da, segment->size); + int offset = segment->da - qproc->mpss_reloc; + void *ptr = NULL; /* Unlock mba before copying segments */ if (!qproc->dump_mba_loaded) { @@ -1210,10 +1220,15 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } } - if (!ptr || ret) - memset(dest, 0xff, segment->size); - else + if (!ret) + ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); + + if (ptr) { memcpy(dest, ptr, segment->size); + iounmap(ptr); + } else { + memset(dest, 0xff, segment->size); + } qproc->dump_segment_mask |= mask; @@ -1548,12 +1563,6 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_size = resource_size(&r); - qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size); - if (!qproc->mpss_region) { - dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", - &r.start, qproc->mpss_size); - return -EBUSY; - } return 0; } -- cgit v1.2.3 From 9666174a4e1a7b1e32c214312678f8452275da6a Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 15 Apr 2020 12:46:19 +0530 Subject: remoteproc: qcom_q6v5_mss: Remove unused q6v5_da_to_va function Remove unsed q6v5_da_to_va function as the mss driver uses a per segment dump function. Tested-by: Evan Green Signed-off-by: Sibi Sankar Link: https://lore.kernel.org/r/20200415071619.6052-2-sibis@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 30652b381c2c..7ca205c242d2 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -190,7 +190,6 @@ struct q6v5 { phys_addr_t mpss_phys; phys_addr_t mpss_reloc; - void *mpss_region; size_t mpss_size; struct qcom_rproc_glink glink_subdev; @@ -1302,18 +1301,6 @@ static int q6v5_stop(struct rproc *rproc) return 0; } -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, size_t len) -{ - struct q6v5 *qproc = rproc->priv; - int offset; - - offset = da - qproc->mpss_reloc; - if (offset < 0 || offset + len > qproc->mpss_size) - return NULL; - - return qproc->mpss_region + offset; -} - static int qcom_q6v5_register_dump_segments(struct rproc *rproc, const struct firmware *mba_fw) { @@ -1361,7 +1348,6 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, static const struct rproc_ops q6v5_ops = { .start = q6v5_start, .stop = q6v5_stop, - .da_to_va = q6v5_da_to_va, .parse_fw = qcom_q6v5_register_dump_segments, .load = q6v5_load, }; -- cgit v1.2.3 From a781e5aa59110d002a56bd41a397c0c8892f0609 Mon Sep 17 00:00:00 2001 From: Rishabh Bhatnagar Date: Wed, 29 Apr 2020 11:04:42 -0700 Subject: remoteproc: core: Prevent system suspend during remoteproc recovery The system might go into suspend during recovery of any remoteproc. This will interrupt the recovery process in between increasing the recovery time. Make the platform device as wakeup capable and use pm_stay_wake/pm_relax APIs to avoid system from going into suspend during recovery. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar Acked-by: Mathieu Poirier Link: https://lore.kernel.org/r/1588183482-21146-1-git-send-email-rishabhb@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 2 ++ drivers/remoteproc/remoteproc_core.c | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 3bb69f58e086..61791a03f648 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -407,6 +407,8 @@ static int adsp_probe(struct platform_device *pdev) adsp->has_aggre2_clk = desc->has_aggre2_clk; platform_set_drvdata(pdev, adsp); + device_wakeup_enable(adsp->dev); + ret = adsp_alloc_memory_region(adsp); if (ret) goto free_rproc; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4bd0f45a00c0..7350161a3ed0 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1766,6 +1766,8 @@ static void rproc_crash_handler_work(struct work_struct *work) if (!rproc->recovery_disabled) rproc_trigger_recovery(rproc); + + pm_relax(rproc->dev.parent); } /** @@ -2353,6 +2355,9 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) return; } + /* Prevent suspend while the remoteproc is being recovered */ + pm_stay_awake(rproc->dev.parent); + dev_err(&rproc->dev, "crash detected in %s: type %s\n", rproc->name, rproc_crash_to_string(type)); -- cgit v1.2.3 From 8a226e2c71bb3763e27a063d36eac5fa4ea53c3f Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Fri, 1 May 2020 21:58:12 +0530 Subject: remoteproc: wcss: add support for rpmsg communication add glink and ssr subdevices for wcss rproc to enable rpmsg communication. Signed-off-by: Sivaprakash Murugesan Link: https://lore.kernel.org/r/1588350492-4663-1-git-send-email-sivaprak@codeaurora.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index f1924b740a10..48d16d81f94d 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -91,6 +91,9 @@ struct q6v5_wcss { phys_addr_t mem_reloc; void *mem_region; size_t mem_size; + + struct qcom_rproc_glink glink_subdev; + struct qcom_rproc_ssr ssr_subdev; }; static int q6v5_wcss_reset(struct q6v5_wcss *wcss) @@ -557,6 +560,9 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (ret) goto free_rproc; + qcom_add_glink_subdev(rproc, &wcss->glink_subdev); + qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss"); + ret = rproc_add(rproc); if (ret) goto free_rproc; -- cgit v1.2.3 From db9178a4f8c4e523f824892cb8bab00961b07385 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 20 Apr 2020 11:05:59 -0500 Subject: remoteproc: Fall back to using parent memory pool if no dedicated available In some cases, like with OMAP remoteproc, we are not creating dedicated memory pool for the virtio device. Instead, we use the same memory pool for all shared memories. The current virtio memory pool handling forces a split between these two, as a separate device is created for it, causing memory to be allocated from bad location if the dedicated pool is not available. Fix this by falling back to using the parent device memory pool if dedicated is not available. Cc: stable@vger.kernel.org Reviewed-by: Mathieu Poirier Acked-by: Arnaud Pouliquen Fixes: 086d08725d34 ("remoteproc: create vdev subdevice with specific dma memory pool") Signed-off-by: Tero Kristo Signed-off-by: Suman Anna Link: https://lore.kernel.org/r/20200420160600.10467-2-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_virtio.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 15ec5fc65257..dfd3808c34fd 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -375,6 +375,18 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) goto out; } } + } else { + struct device_node *np = rproc->dev.parent->of_node; + + /* + * If we don't have dedicated buffer, just attempt to re-assign + * the reserved memory from our parent. A default memory-region + * at index 0 from the parent's memory-regions is assigned for + * the rvdev dev to allocate from. Failure is non-critical and + * the allocations will fall back to global pools, so don't + * check return value either. + */ + of_reserved_mem_device_init_by_idx(dev, np, 0); } /* Allocate virtio device */ -- cgit v1.2.3 From c774ad010873bb89dcc0cdcb1e96aef6664d8caf Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Apr 2020 11:06:00 -0500 Subject: remoteproc: Fix and restore the parenting hierarchy for vdev The commit 086d08725d34 ("remoteproc: create vdev subdevice with specific dma memory pool") has introduced a new vdev subdevice for each vdev declared in the firmware resource table and made it as the parent for the created virtio rpmsg devices instead of the previous remoteproc device. This changed the overall parenting hierarchy for the rpmsg devices, which were children of virtio devices, and does not allow the corresponding rpmsg drivers to retrieve the parent rproc device through the rproc_get_by_child() API. Fix this by restoring the remoteproc device as the parent. The new vdev subdevice can continue to inherit the DMA attributes from the remoteproc's parent device (actual platform device). Cc: stable@vger.kernel.org Fixes: 086d08725d34 ("remoteproc: create vdev subdevice with specific dma memory pool") Signed-off-by: Suman Anna Reviewed-by: Mathieu Poirier Acked-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20200420160600.10467-3-s-anna@ti.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 7350161a3ed0..9c6d9ff7a1fc 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -517,7 +517,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, /* Initialise vdev subdevice */ snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index); - rvdev->dev.parent = rproc->dev.parent; + rvdev->dev.parent = &rproc->dev; rvdev->dev.dma_pfn_offset = rproc->dev.parent->dma_pfn_offset; rvdev->dev.release = rproc_rvdev_release; dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name); -- cgit v1.2.3 From 25f9f5a2107fdc6510463be4e55012d17d83ab2b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 14 May 2020 11:58:56 -0700 Subject: remoteproc: wcss: Fix arguments passed to qcom_add_glink_subdev() Recently qcom_add_glink_subdev() was extended to also take the glink_ssr identifier as an argument and I missed this while applying '8a226e2c71bb ("remoteproc: wcss: add support for rpmsg communication")'. Fixes: 8a226e2c71bb ("remoteproc: wcss: add support for rpmsg communication") Reported-by: kbuild test robot Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20200514185856.1598945-1-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 48d16d81f94d..88c76b9417fa 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -560,7 +560,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (ret) goto free_rproc; - qcom_add_glink_subdev(rproc, &wcss->glink_subdev); + qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss"); qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss"); ret = rproc_add(rproc); -- cgit v1.2.3 From a99a37f6cd5a74d5b22c08544aa6c5890813c8ba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 15 May 2020 12:43:38 +0200 Subject: remoteproc: Add support for runtime PM Call pm_runtime_get_sync() before the firmware is loaded, and pm_runtime_put() after the remote processor has been stopped. Even though the remoteproc device has no PM callbacks, this allows the parent device's PM callbacks to be properly called. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20200515104340.10473-3-paul@crapouillou.net Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9c6d9ff7a1fc..0cc015fabf78 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1382,6 +1383,12 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) if (ret) return ret; + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "pm_runtime_get_sync failed: %d\n", ret); + return ret; + } + dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); /* @@ -1391,7 +1398,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) ret = rproc_enable_iommu(rproc); if (ret) { dev_err(dev, "can't enable iommu: %d\n", ret); - return ret; + goto put_pm_runtime; } /* Prepare rproc for firmware loading if needed */ @@ -1445,6 +1452,8 @@ unprepare_rproc: rproc_unprepare_device(rproc); disable_iommu: rproc_disable_iommu(rproc); +put_pm_runtime: + pm_runtime_put(dev); return ret; } @@ -1882,6 +1891,8 @@ void rproc_shutdown(struct rproc *rproc) rproc_disable_iommu(rproc); + pm_runtime_put(dev); + /* Free the copy of the resource table */ kfree(rproc->cached_table); rproc->cached_table = NULL; @@ -2172,6 +2183,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, rproc->state = RPROC_OFFLINE; + pm_runtime_no_callbacks(&rproc->dev); + pm_runtime_enable(&rproc->dev); + return rproc; put_device: @@ -2191,6 +2205,7 @@ EXPORT_SYMBOL(rproc_alloc); */ void rproc_free(struct rproc *rproc) { + pm_runtime_disable(&rproc->dev); put_device(&rproc->dev); } EXPORT_SYMBOL(rproc_free); -- cgit v1.2.3 From 48f0a1bbb7586c94e0f15116b06f8179df2fd60f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 15 May 2020 12:43:39 +0200 Subject: remoteproc: ingenic: Added remoteproc driver This driver is used to boot, communicate with and load firmwares to the MIPS co-processor found in the VPU hardware of the JZ47xx SoCs from Ingenic. Signed-off-by: Paul Cercueil Acked-by: Mathieu Poirier Link: https://lore.kernel.org/r/20200515104340.10473-4-paul@crapouillou.net Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 9 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/ingenic_rproc.c | 280 +++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 drivers/remoteproc/ingenic_rproc.c (limited to 'drivers') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index fbaed079b299..c4d1731295eb 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -23,6 +23,15 @@ config IMX_REMOTEPROC It's safe to say N here. +config INGENIC_VPU_RPROC + tristate "Ingenic JZ47xx VPU remoteproc support" + depends on MIPS || COMPILE_TEST + help + Say y or m here to support the VPU in the JZ47xx SoCs from Ingenic. + + This can be either built-in or a loadable module. + If unsure say N. + config MTK_SCP tristate "Mediatek SCP support" depends on ARCH_MEDIATEK diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 0effd3825035..e8b886e511f0 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -10,6 +10,7 @@ remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o +obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c new file mode 100644 index 000000000000..189020d77b25 --- /dev/null +++ b/drivers/remoteproc/ingenic_rproc.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Ingenic JZ47xx remoteproc driver + * Copyright 2019, Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "remoteproc_internal.h" + +#define REG_AUX_CTRL 0x0 +#define REG_AUX_MSG_ACK 0x10 +#define REG_AUX_MSG 0x14 +#define REG_CORE_MSG_ACK 0x18 +#define REG_CORE_MSG 0x1C + +#define AUX_CTRL_SLEEP BIT(31) +#define AUX_CTRL_MSG_IRQ_EN BIT(3) +#define AUX_CTRL_NMI_RESETS BIT(2) +#define AUX_CTRL_NMI BIT(1) +#define AUX_CTRL_SW_RESET BIT(0) + +struct vpu_mem_map { + const char *name; + unsigned int da; +}; + +struct vpu_mem_info { + const struct vpu_mem_map *map; + unsigned long len; + void __iomem *base; +}; + +static const struct vpu_mem_map vpu_mem_map[] = { + { "tcsm0", 0x132b0000 }, + { "tcsm1", 0xf4000000 }, + { "sram", 0x132f0000 }, +}; + +/** + * struct vpu - Ingenic VPU remoteproc private structure + * @irq: interrupt number + * @clks: pointers to the VPU and AUX clocks + * @aux_base: raw pointer to the AUX interface registers + * @mem_info: array of struct vpu_mem_info, which contain the mapping info of + * each of the external memories + * @dev: private pointer to the device + */ +struct vpu { + int irq; + struct clk_bulk_data clks[2]; + void __iomem *aux_base; + struct vpu_mem_info mem_info[ARRAY_SIZE(vpu_mem_map)]; + struct device *dev; +}; + +static int ingenic_rproc_start(struct rproc *rproc) +{ + struct vpu *vpu = rproc->priv; + u32 ctrl; + + enable_irq(vpu->irq); + + /* Reset the AUX and enable message IRQ */ + ctrl = AUX_CTRL_NMI_RESETS | AUX_CTRL_NMI | AUX_CTRL_MSG_IRQ_EN; + writel(ctrl, vpu->aux_base + REG_AUX_CTRL); + + return 0; +} + +static int ingenic_rproc_stop(struct rproc *rproc) +{ + struct vpu *vpu = rproc->priv; + + disable_irq(vpu->irq); + + /* Keep AUX in reset mode */ + writel(AUX_CTRL_SW_RESET, vpu->aux_base + REG_AUX_CTRL); + + return 0; +} + +static void ingenic_rproc_kick(struct rproc *rproc, int vqid) +{ + struct vpu *vpu = rproc->priv; + + writel(vqid, vpu->aux_base + REG_CORE_MSG); +} + +static void *ingenic_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +{ + struct vpu *vpu = rproc->priv; + void __iomem *va = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vpu_mem_map); i++) { + const struct vpu_mem_info *info = &vpu->mem_info[i]; + const struct vpu_mem_map *map = info->map; + + if (da >= map->da && (da + len) < (map->da + info->len)) { + va = info->base + (da - map->da); + break; + } + } + + return (__force void *)va; +} + +static struct rproc_ops ingenic_rproc_ops = { + .start = ingenic_rproc_start, + .stop = ingenic_rproc_stop, + .kick = ingenic_rproc_kick, + .da_to_va = ingenic_rproc_da_to_va, +}; + +static irqreturn_t vpu_interrupt(int irq, void *data) +{ + struct rproc *rproc = data; + struct vpu *vpu = rproc->priv; + u32 vring; + + vring = readl(vpu->aux_base + REG_AUX_MSG); + + /* Ack the interrupt */ + writel(0, vpu->aux_base + REG_AUX_MSG_ACK); + + return rproc_vq_interrupt(rproc, vring); +} + +static void ingenic_rproc_disable_clks(void *data) +{ + struct vpu *vpu = data; + + pm_runtime_resume(vpu->dev); + pm_runtime_disable(vpu->dev); + + clk_bulk_disable_unprepare(ARRAY_SIZE(vpu->clks), vpu->clks); +} + +static int ingenic_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *mem; + struct rproc *rproc; + struct vpu *vpu; + unsigned int i; + int ret; + + rproc = devm_rproc_alloc(dev, "ingenic-vpu", + &ingenic_rproc_ops, NULL, sizeof(*vpu)); + if (!rproc) + return -ENOMEM; + + vpu = rproc->priv; + vpu->dev = &pdev->dev; + platform_set_drvdata(pdev, vpu); + + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aux"); + vpu->aux_base = devm_ioremap_resource(dev, mem); + if (IS_ERR(vpu->aux_base)) { + dev_err(dev, "Failed to ioremap\n"); + return PTR_ERR(vpu->aux_base); + } + + for (i = 0; i < ARRAY_SIZE(vpu_mem_map); i++) { + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, + vpu_mem_map[i].name); + + vpu->mem_info[i].base = devm_ioremap_resource(dev, mem); + if (IS_ERR(vpu->mem_info[i].base)) { + ret = PTR_ERR(vpu->mem_info[i].base); + dev_err(dev, "Failed to ioremap\n"); + return ret; + } + + vpu->mem_info[i].len = resource_size(mem); + vpu->mem_info[i].map = &vpu_mem_map[i]; + } + + vpu->clks[0].id = "vpu"; + vpu->clks[1].id = "aux"; + + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(vpu->clks), vpu->clks); + if (ret) { + dev_err(dev, "Failed to get clocks\n"); + return ret; + } + + vpu->irq = platform_get_irq(pdev, 0); + if (vpu->irq < 0) + return vpu->irq; + + ret = devm_request_irq(dev, vpu->irq, vpu_interrupt, 0, "VPU", rproc); + if (ret < 0) { + dev_err(dev, "Failed to request IRQ\n"); + return ret; + } + + disable_irq(vpu->irq); + + /* The clocks must be enabled for the firmware to be loaded in TCSM */ + ret = clk_bulk_prepare_enable(ARRAY_SIZE(vpu->clks), vpu->clks); + if (ret) { + dev_err(dev, "Unable to start clocks\n"); + return ret; + } + + pm_runtime_irq_safe(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + pm_runtime_use_autosuspend(dev); + + ret = devm_add_action_or_reset(dev, ingenic_rproc_disable_clks, vpu); + if (ret) { + dev_err(dev, "Unable to register action\n"); + goto out_pm_put; + } + + ret = devm_rproc_add(dev, rproc); + if (ret) { + dev_err(dev, "Failed to register remote processor\n"); + goto out_pm_put; + } + +out_pm_put: + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static const struct of_device_id ingenic_rproc_of_matches[] = { + { .compatible = "ingenic,jz4770-vpu-rproc", }, + {} +}; +MODULE_DEVICE_TABLE(of, ingenic_rproc_of_matches); + +static int __maybe_unused ingenic_rproc_suspend(struct device *dev) +{ + struct vpu *vpu = dev_get_drvdata(dev); + + clk_bulk_disable(ARRAY_SIZE(vpu->clks), vpu->clks); + + return 0; +} + +static int __maybe_unused ingenic_rproc_resume(struct device *dev) +{ + struct vpu *vpu = dev_get_drvdata(dev); + + return clk_bulk_enable(ARRAY_SIZE(vpu->clks), vpu->clks); +} + +static const struct dev_pm_ops __maybe_unused ingenic_rproc_pm = { + SET_RUNTIME_PM_OPS(ingenic_rproc_suspend, ingenic_rproc_resume, NULL) +}; + +static struct platform_driver ingenic_rproc_driver = { + .probe = ingenic_rproc_probe, + .driver = { + .name = "ingenic-vpu", +#ifdef CONFIG_PM + .pm = &ingenic_rproc_pm, +#endif + .of_match_table = ingenic_rproc_of_matches, + }, +}; +module_platform_driver(ingenic_rproc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul Cercueil "); +MODULE_DESCRIPTION("Ingenic JZ47xx Remote Processor control driver"); -- cgit v1.2.3 From 7dcef3988eedbfb40e7e95a821966a029a5a465b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 20 May 2020 15:07:05 +0300 Subject: remoteproc: Fix an error code in devm_rproc_alloc() The comments say that this function should return NULL on error and the caller expects NULL returns as well so I have modified the code to match. Returning an ERR_PTR(-ENOMEM) would lead to an OOps. Reviewed-by: Paul Cercueil Reviewed-by: Bjorn Andersson Fixes: 305ac5a766b1 ("remoteproc: Add device-managed variants of rproc_alloc/rproc_add") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20200520120705.GH172354@mwanda Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 0cc015fabf78..9f04c30c4aaf 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2297,7 +2297,7 @@ struct rproc *devm_rproc_alloc(struct device *dev, const char *name, ptr = devres_alloc(devm_rproc_free, sizeof(*ptr), GFP_KERNEL); if (!ptr) - return ERR_PTR(-ENOMEM); + return NULL; rproc = rproc_alloc(dev, name, ops, firmware, len); if (rproc) { -- cgit v1.2.3