From 39d0447e5fc86ff5cac11726e130c7368f8235a6 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Wed, 24 Apr 2024 14:35:04 +0800 Subject: [PATCH 01/11] driver: remoteproc: improve stop function. The stop function is divided into the following steps: 1. use reserved[0] in resource table as stop flag, and set this flag when the stop function is called; 2. send ipi to remote processor, and wait for the remote processor to shut down the CPU; 3. clear the stop flag. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 61 ++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 71f54cb79a5..beb8aa36b56 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include "remoteproc_internal.h" @@ -30,10 +33,16 @@ #define AFFINITY_INFO 0xc4000004 #define MIGRATE 0xc4000005 +#define REMOTE_PROC_STOP 0x0001U + +/* wait for 1s */ +#define HOMO_MAX_WAIT_TIME_NS (1000 * NSEC_PER_MSEC) + /* Resource table for the homo remote processors */ struct homo_resource_table { unsigned int version; unsigned int num; + /* use bit0 of reserved[0] as stop flag */ unsigned int reserved[2]; unsigned int offset[RPROC_RESOURCE_ENTRIES]; @@ -63,6 +72,16 @@ static struct work_struct workqueue; #define MPIDR_TO_SGI_AFFINITY(cluster_id, level) (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) +static bool homo_rproc_wait_cpuoff(struct rproc *rproc, ktime_t stop) +{ + int err = 0; + struct homo_rproc *priv = rproc->priv; + + err = psci_ops.affinity_info(cpu_logical_map(priv->cpu), 0); + + return (err == 1) || ktime_after(ktime_get(), stop); +} + void gicv3_ipi_send_single(int irq, u64 mpidr) { u16 tlist = 0; @@ -86,6 +105,20 @@ void gicv3_ipi_send_single(int irq, u64 mpidr) isb(); } +static void homo_rproc_write_stop_flag(struct homo_resource_table *table_ptr) +{ + unsigned int *flag = table_ptr->reserved; + + *flag |= REMOTE_PROC_STOP; +} + +static void homo_rproc_clear_stop_flag(struct homo_resource_table *table_ptr) +{ + unsigned int *flag = table_ptr->reserved; + + *flag &= ~REMOTE_PROC_STOP; +} + static void homo_rproc_vq_irq(struct work_struct *work) { struct homo_rproc *priv = g_priv; @@ -120,12 +153,32 @@ static int homo_rproc_start(struct rproc *rproc) static int homo_rproc_stop(struct rproc *rproc) { - int err; struct homo_rproc *priv = rproc->priv; + ktime_t stop; - err = psci_ops.affinity_info(cpu_logical_map(priv->cpu), 0); - if (err == 1) - add_cpu(priv->cpu); + if (!priv || !priv->rsc) { + dev_err(&rproc->dev, "cannot find resource table!\n"); + return -1; + } + + homo_rproc_write_stop_flag(priv->rsc); + __flush_dcache_area(rproc->table_ptr, rproc->table_sz); + + gicv3_ipi_send_single(priv->irq, cpu_logical_map(priv->cpu)); + + stop = ktime_add_ns(ktime_get(), HOMO_MAX_WAIT_TIME_NS); + + spin_until_cond(homo_rproc_wait_cpuoff(rproc, stop)); + + if (ktime_after(ktime_get(), stop)) { + dev_err(&rproc->dev, "wait remote processor stop timeout!\n"); + return -1; + } + + add_cpu(priv->cpu); + + homo_rproc_clear_stop_flag(priv->rsc); + __flush_dcache_area(rproc->table_ptr, rproc->table_sz); return 0; } -- Gitee From 9b007edcbbdfedb3d476266ac23f208614d58c5f Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:03:21 +0800 Subject: [PATCH 02/11] driver: remoteproc: remove the workqueue remove the workqueue and instead run rproc_vq_interrupt directly in the interrupt handler, which can shorten the processing time. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index beb8aa36b56..7735eb38082 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -68,13 +68,12 @@ struct homo_rproc { static int homo_rproc_irq; static struct homo_rproc *g_priv; -static struct work_struct workqueue; #define MPIDR_TO_SGI_AFFINITY(cluster_id, level) (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) static bool homo_rproc_wait_cpuoff(struct rproc *rproc, ktime_t stop) { - int err = 0; + int err; struct homo_rproc *priv = rproc->priv; err = psci_ops.affinity_info(cpu_logical_map(priv->cpu), 0); @@ -119,15 +118,6 @@ static void homo_rproc_clear_stop_flag(struct homo_resource_table *table_ptr) *flag &= ~REMOTE_PROC_STOP; } -static void homo_rproc_vq_irq(struct work_struct *work) -{ - struct homo_rproc *priv = g_priv; - struct homo_resource_table *rsc = priv->rsc; - struct rproc *rproc = priv->rproc; - - rproc_vq_interrupt(rproc, rsc->rpmsg_vring0.notifyid); -} - static int homo_rproc_start(struct rproc *rproc) { int err; @@ -139,8 +129,6 @@ static int homo_rproc_start(struct rproc *rproc) if (err == 0) remove_cpu(priv->cpu); - INIT_WORK(&workqueue, homo_rproc_vq_irq); - priv->rsc = (struct homo_resource_table *)rproc->table_ptr; /* ARMv8 requires to clean D-cache and invalidate I-cache for memory containing new instructions. */ @@ -239,7 +227,12 @@ static void __iomem *homo_ioremap_prot(phys_addr_t addr, size_t size, pgprot_t p static irqreturn_t homo_rproc_irq_handler(int irq, void *data) { - schedule_work(&workqueue); + struct homo_rproc *priv = g_priv; + struct homo_resource_table *rsc = priv->rsc; + struct rproc *rproc = priv->rproc; + + rproc_vq_interrupt(rproc, rsc->rpmsg_vring0.notifyid); + return IRQ_HANDLED; } -- Gitee From 1e2f7a90b1cdd899afa748f8f85cca6c8dc78cd6 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:43:54 +0800 Subject: [PATCH 03/11] driver: remoteproc: support two remote processors. The new function is divided into the following parts: 1. create up to two rproc devices by identifying DTS child nodes; 2. change the original static variable 'g_priv' to an array, corresponding to different rproc devices respectively; 3. distinguish between different rproc devices in the common handler function. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 186 +++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 27 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 7735eb38082..e69192bb988 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -21,11 +21,14 @@ #include #include #include +#include #include "remoteproc_internal.h" #define RPROC_RESOURCE_ENTRIES 8 +#define RPROC_CORE_MAX_NUM 2 + #define PSCI_VERSION 0x84000000 #define CPU_SUSPEND 0xc4000001 #define CPU_OFF 0x84000002 @@ -64,13 +67,41 @@ struct homo_rproc { int irq; int cpu; + int rproc_irq; }; -static int homo_rproc_irq; -static struct homo_rproc *g_priv; +static struct homo_rproc *g_homo_rproc[RPROC_CORE_MAX_NUM]; +static int homo_rproc_num; +static int homo_rproc_offset; #define MPIDR_TO_SGI_AFFINITY(cluster_id, level) (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) +static int homo_find_rproc_offset_cpu(int cpu) +{ + int i; + + for(i = 0; i < homo_rproc_num; i++) { + if (g_homo_rproc[i]->cpu == cpu) { + return i; + } + } + + return -1; +} + +static int homo_find_rproc_offset_irq(int rproc_irq) +{ + int i; + + for(i = 0; i < homo_rproc_num; i++) { + if (g_homo_rproc[i]->rproc_irq == rproc_irq) { + return i; + } + } + + return -1; +} + static bool homo_rproc_wait_cpuoff(struct rproc *rproc, ktime_t stop) { int err; @@ -124,11 +155,15 @@ static int homo_rproc_start(struct rproc *rproc) struct homo_rproc *priv = rproc->priv; int phys_cpuid = cpu_logical_map(priv->cpu); struct arm_smccc_res smc_res; + int offset; err = psci_ops.affinity_info(phys_cpuid, 0); if (err == 0) remove_cpu(priv->cpu); + offset = homo_find_rproc_offset_cpu(priv->cpu); + homo_rproc_offset = offset; + priv->rsc = (struct homo_resource_table *)rproc->table_ptr; /* ARMv8 requires to clean D-cache and invalidate I-cache for memory containing new instructions. */ @@ -227,39 +262,60 @@ static void __iomem *homo_ioremap_prot(phys_addr_t addr, size_t size, pgprot_t p static irqreturn_t homo_rproc_irq_handler(int irq, void *data) { - struct homo_rproc *priv = g_priv; - struct homo_resource_table *rsc = priv->rsc; - struct rproc *rproc = priv->rproc; + int offset; + struct homo_rproc *priv; + struct homo_resource_table *rsc; + struct rproc *rproc; - rproc_vq_interrupt(rproc, rsc->rpmsg_vring0.notifyid); + offset = homo_find_rproc_offset_irq(irq); + priv = g_homo_rproc[offset]; + rsc = priv->rsc; + rproc = priv->rproc; + rproc_vq_interrupt(rproc, rsc->rpmsg_vring0.notifyid); return IRQ_HANDLED; } static int homo_rproc_starting_cpu(unsigned int cpu) { - enable_percpu_irq(homo_rproc_irq, irq_get_trigger_type(homo_rproc_irq)); + int i; + int irq; + + for(i = 0; i < homo_rproc_num; i++) { + irq = g_homo_rproc[i]->rproc_irq; + enable_percpu_irq(irq, irq_get_trigger_type(irq)); + } return 0; } static int homo_rproc_dying_cpu(unsigned int cpu) { - disable_percpu_irq(homo_rproc_irq); + int i; + int irq; + + for(i = 0; i < homo_rproc_num; i++) { + irq = g_homo_rproc[i]->rproc_irq; + disable_percpu_irq(irq); + } return 0; } -static int homo_rproc_probe(struct platform_device *pdev) +static int homo_core_of_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node, *p; + struct device_node *np = dev_of_node(dev), *p; struct device_node *np_mem; struct resource res; - struct rproc *rproc; - const char *fw_name; struct homo_rproc *priv; - int ret; unsigned int ipi, cpu; + int ret; struct of_phandle_args oirq; + int rproc_irq; + struct rproc *rproc; + const char *fw_name; + + if (!devres_open_group(dev, homo_core_of_init, GFP_KERNEL)) + return -ENOMEM; ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret) { @@ -276,7 +332,7 @@ static int homo_rproc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rproc); - priv = g_priv = rproc->priv; + priv = g_homo_rproc[homo_rproc_num] = rproc->priv; priv->rproc = rproc; /* The following values can be modified through devicetree 'homo_rproc' node */ @@ -327,43 +383,119 @@ static int homo_rproc_probe(struct platform_device *pdev) p = of_irq_find_parent(np); if (p == NULL) { ret = -EINVAL; - goto err; + goto err_free; } oirq.np = p; oirq.args_count = 1; oirq.args[0] = ipi; - homo_rproc_irq = irq_create_of_mapping(&oirq); - if (homo_rproc_irq <= 0) { + rproc_irq = irq_create_of_mapping(&oirq); + if (rproc_irq <= 0) { ret = -EINVAL; goto err; } - ret = request_percpu_irq(homo_rproc_irq, homo_rproc_irq_handler, "homo-rproc-ipi", &cpu_number); - if (ret) { - dev_err(dev, "failed to request percpu irq, status = %d\n", ret); - goto err; - } + priv->rproc_irq = rproc_irq; - ret = cpuhp_setup_state(CPUHP_AP_HOMO_RPROC_STARTING, "remoteproc/homo_rproc:starting", homo_rproc_starting_cpu, homo_rproc_dying_cpu); + ret = request_percpu_irq(rproc_irq, homo_rproc_irq_handler, "homo-rproc-ipi", &cpu_number); if (ret) { - dev_err(dev, "cpuhp setup state failed, status = %d\n", ret); - goto err; + dev_err(dev, "failed to request percpu irq, status = %d\n", ret); + goto err_free; } ret = rproc_add(rproc); if (ret) { dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", ret); - goto err; + goto err_free; } + devres_close_group(dev, homo_core_of_init); + return 0; -err: +err_free: vunmap((void *)((unsigned long)priv->addr & PAGE_MASK)); + +err: + devres_release_group(dev, homo_core_of_init); return ret; } +static int homo_cluster_of_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev_of_node(dev); + struct platform_device *cpdev; + struct device_node *child; + int ret; + + for_each_available_child_of_node(np, child) { + const char *node_name = child->name; + cpdev = of_find_device_by_node(child); + if (!cpdev) { + ret = -ENODEV; + dev_err(dev, "could not get core platform device for node %s\n", node_name); + of_node_put(child); + goto fail; + } + + ret = homo_core_of_init(cpdev); + if (ret) { + dev_err(dev, "homo_core_of_init failed, ret = %d\n", + ret); + put_device(&cpdev->dev); + of_node_put(child); + goto fail; + } + + homo_rproc_num++; + put_device(&cpdev->dev); + } + + return 0; + +fail: + return ret; +} + +static int homo_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret; + int num_cores; + + num_cores = of_get_available_child_count(np); + + dev_info(dev, "num_cores = %d\n", num_cores); + + if (num_cores > RPROC_CORE_MAX_NUM) { + dev_err(dev, "core number (%d) out of range\n", num_cores); + return -ENODEV; + } + + ret = devm_of_platform_populate(dev); + if (ret) { + dev_err(dev, "devm_of_platform_populate failed, ret = %d\n", + ret); + return ret; + } + + ret = homo_cluster_of_init(pdev); + if (ret) { + dev_err(dev, "homo_cluster_of_init failed, ret = %d\n", ret); + return ret; + } + + ret = cpuhp_setup_state(CPUHP_AP_HOMO_RPROC_STARTING, "remoteproc/homo_rproc:starting", homo_rproc_starting_cpu, homo_rproc_dying_cpu); + if (ret) { + dev_err(dev, "cpuhp setup state failed, status = %d\n", ret); + return ret; + } + + return 0; +} + static int homo_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); -- Gitee From 03efcf6f4d14b8c840ee2c157d673d6a904c8c91 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:45:54 +0800 Subject: [PATCH 04/11] driver: remoteproc: add exit functions to be used when initialization fails. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index e69192bb988..0662cc1625c 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -421,6 +421,32 @@ static int homo_core_of_init(struct platform_device *pdev) return ret; } +/* + * free the resources when init fail + */ +static void homo_core_of_exit(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + platform_set_drvdata(pdev, NULL); + devres_release_group(dev, homo_core_of_init); +} + +static void homo_cluster_of_exit(struct platform_device *pdev) +{ + struct rproc *rproc; + struct platform_device *cpdev; + int i; + + for(i = 0; i < homo_rproc_num; i++) { + rproc = g_homo_rproc[i]->rproc; + cpdev = to_platform_device(rproc->dev.parent); + homo_core_of_exit(cpdev); + } + + homo_rproc_num = 0; +} + static int homo_cluster_of_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -455,6 +481,7 @@ static int homo_cluster_of_init(struct platform_device *pdev) return 0; fail: + homo_cluster_of_exit(pdev); return ret; } -- Gitee From ee99a33e0a0e0e69734b0d4abe6c574c3c4486c0 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:51:02 +0800 Subject: [PATCH 05/11] driver: remoteproc: add CPU checking in the interrupt handler. Only the specified CPU will execute the code, and other CPUs will return directly. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 0662cc1625c..1087ed5aba7 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -27,8 +27,12 @@ #define RPROC_RESOURCE_ENTRIES 8 +/* Support up to two cores */ #define RPROC_CORE_MAX_NUM 2 +/* cpu0 handling interrupt */ +#define RPROC_IRQ_HANDLE_CPU 0 + #define PSCI_VERSION 0x84000000 #define CPU_SUSPEND 0xc4000001 #define CPU_OFF 0x84000002 @@ -266,6 +270,12 @@ static irqreturn_t homo_rproc_irq_handler(int irq, void *data) struct homo_rproc *priv; struct homo_resource_table *rsc; struct rproc *rproc; + int cpu = smp_processor_id(); + + /* Return immediately if not the designated CPU */ + if (cpu != RPROC_IRQ_HANDLE_CPU) { + return IRQ_HANDLED; + } offset = homo_find_rproc_offset_irq(irq); priv = g_homo_rproc[offset]; -- Gitee From 18932b3975a46f6b067c2783f77a1eb51cc0d3d3 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:53:02 +0800 Subject: [PATCH 06/11] driver: remoteproc: remove redundant code and macro definitions. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 1087ed5aba7..570869c268e 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -33,12 +33,7 @@ /* cpu0 handling interrupt */ #define RPROC_IRQ_HANDLE_CPU 0 -#define PSCI_VERSION 0x84000000 -#define CPU_SUSPEND 0xc4000001 -#define CPU_OFF 0x84000002 #define CPU_ON 0xc4000003 -#define AFFINITY_INFO 0xc4000004 -#define MIGRATE 0xc4000005 #define REMOTE_PROC_STOP 0x0001U @@ -76,23 +71,9 @@ struct homo_rproc { static struct homo_rproc *g_homo_rproc[RPROC_CORE_MAX_NUM]; static int homo_rproc_num; -static int homo_rproc_offset; #define MPIDR_TO_SGI_AFFINITY(cluster_id, level) (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) -static int homo_find_rproc_offset_cpu(int cpu) -{ - int i; - - for(i = 0; i < homo_rproc_num; i++) { - if (g_homo_rproc[i]->cpu == cpu) { - return i; - } - } - - return -1; -} - static int homo_find_rproc_offset_irq(int rproc_irq) { int i; @@ -159,15 +140,11 @@ static int homo_rproc_start(struct rproc *rproc) struct homo_rproc *priv = rproc->priv; int phys_cpuid = cpu_logical_map(priv->cpu); struct arm_smccc_res smc_res; - int offset; err = psci_ops.affinity_info(phys_cpuid, 0); if (err == 0) remove_cpu(priv->cpu); - offset = homo_find_rproc_offset_cpu(priv->cpu); - homo_rproc_offset = offset; - priv->rsc = (struct homo_resource_table *)rproc->table_ptr; /* ARMv8 requires to clean D-cache and invalidate I-cache for memory containing new instructions. */ -- Gitee From e6c6976a7bffcc63daf6bce76c27a2c76ce4a87f Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 11:56:04 +0800 Subject: [PATCH 07/11] driver: remoteproc: rename the struct variable to indicate it is a mapped interrupt Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 570869c268e..c9a8ef7b604 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -66,7 +66,7 @@ struct homo_rproc { int irq; int cpu; - int rproc_irq; + int mapped_irq; }; static struct homo_rproc *g_homo_rproc[RPROC_CORE_MAX_NUM]; @@ -79,7 +79,7 @@ static int homo_find_rproc_offset_irq(int rproc_irq) int i; for(i = 0; i < homo_rproc_num; i++) { - if (g_homo_rproc[i]->rproc_irq == rproc_irq) { + if (g_homo_rproc[i]->mapped_irq == rproc_irq) { return i; } } @@ -269,7 +269,7 @@ static int homo_rproc_starting_cpu(unsigned int cpu) int irq; for(i = 0; i < homo_rproc_num; i++) { - irq = g_homo_rproc[i]->rproc_irq; + irq = g_homo_rproc[i]->mapped_irq; enable_percpu_irq(irq, irq_get_trigger_type(irq)); } return 0; @@ -281,7 +281,7 @@ static int homo_rproc_dying_cpu(unsigned int cpu) int irq; for(i = 0; i < homo_rproc_num; i++) { - irq = g_homo_rproc[i]->rproc_irq; + irq = g_homo_rproc[i]->mapped_irq; disable_percpu_irq(irq); } return 0; @@ -382,7 +382,7 @@ static int homo_core_of_init(struct platform_device *pdev) goto err; } - priv->rproc_irq = rproc_irq; + priv->mapped_irq = rproc_irq; ret = request_percpu_irq(rproc_irq, homo_rproc_irq_handler, "homo-rproc-ipi", &cpu_number); if (ret) { -- Gitee From 42202759159bae7a9638c5a6df62b25fd5719896 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 14:03:47 +0800 Subject: [PATCH 08/11] remoteproc: dt-bindings: add child node descriptions to support up to two remote processors Signed-off-by: huyuming1672 --- .../bindings/remoteproc/homo-rproc.txt | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt b/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt index 00f4c4402ec..f605fe2e87c 100644 --- a/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt +++ b/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt @@ -7,13 +7,15 @@ Homogeneous RemoteProc Device Node: ================================= A homo_remoteproc device node is used to represent the remote core instance within SoC. +The parent node defines up to two child nodes, each representing a remote processor. + Required properties: -------------------- - - compatible : should be "homo,rproc" + - compatible : the parent node should be "homo,rproc", and the child node can be "homo,rproc-core" - remote-processor: remote processor's linux cpu logical number - - inter-processor-interrupt: IPI/SGI interrupt number, default is 9 + - inter-processor-interrupt: IPI/SGI interrupt number - memory-region: reserved memory which will be used by remote processor - - firmware-name: the name of openamp image, default is "openamp_core0.elf" + - firmware-name: the name of openamp image Example: -------- @@ -22,18 +24,31 @@ Example: #address-cells = <0x2>; #size-cells = <0x2>; ranges; - - rproc: rproc@b0100000 { + rproc0: rproc0@b0100000 { no-map; reg = <0x0 0xb0100000 0x0 0x19900000>; }; + rproc1: rpro1c@d0100000 { + no-map; + reg = <0x0 0xd0100000 0x0 0x19900000>; + }; }; homo_rproc: homo_rproc@0 { compatible = "homo,rproc"; - remote-processor = <3>; - inter-processor-interrupt = <9>; - memory-region = <&rproc>; - firmware-name = "openamp_core0.elf"; status = "disabled"; + homo_core0: homo_core0@b0100000 { + compatible = "homo,rproc-core"; + remote-processor = <3>; + inter-processor-interrupt = <9>; + memory-region = <&rproc0>; + firmware-name = "openamp_core0.elf"; + }; + homo_core1: homo_core1@d0100000 { + compatible = "homo,rproc-core"; + remote-processor = <2>; + inter-processor-interrupt = <10>; + memory-region = <&rproc1>; + firmware-name = "openamp_core1.elf"; + }; }; -- Gitee From 62cde80e5c4f7a60503ff6d44ce07e5b91713404 Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 24 May 2024 15:45:43 +0800 Subject: [PATCH 09/11] driver: remoteproc: further refine the exception exit When an error occurs during code execution and rproc_alloc has already been executed or when the driver is removed, call functions rproc_del and rproc_free. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index c9a8ef7b604..b46c36b011a 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -325,18 +325,21 @@ static int homo_core_of_init(struct platform_device *pdev) /* The following values can be modified through devicetree 'homo_rproc' node */ if (of_property_read_u32(np, "remote-processor", &cpu)) { dev_err(dev, "not found 'remote-processor' property\n"); - return -EINVAL; + ret = -EINVAL; + goto err_add; } if (of_property_read_u32(np, "inter-processor-interrupt", &ipi)) { dev_err(dev, "not found 'inter-processor-interrupt' property\n"); - return -EINVAL; + ret = -EINVAL; + goto err_add; } /* The gic-v3 driver has registered the 0-7 range of SGI interrupt for system purpose */ if (ipi < 8) { dev_err(dev, "'inter-processor-interrupt' is %d, should be between 9~15\n", ipi); - return -EINVAL; + ret = -EINVAL; + goto err_add; } priv->cpu = cpu; @@ -348,7 +351,7 @@ static int homo_core_of_init(struct platform_device *pdev) ret = of_address_to_resource(np_mem, 0, &res); if (ret) { dev_err(dev, "can't find memory-region for Baremetal\n"); - return ret; + goto err_add; } priv->rsc = NULL; @@ -361,7 +364,8 @@ static int homo_core_of_init(struct platform_device *pdev) priv->addr = homo_ioremap_prot(priv->phys_addr, priv->size, PAGE_KERNEL_EXEC); if (!priv->addr) { dev_err(dev, "ioremap failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_add; } dev_info(dev, "ioremap: phys_addr = %016llx, addr = %llx, size = %lld\n", priv->phys_addr, (u64)(priv->addr), priv->size); @@ -403,6 +407,10 @@ static int homo_core_of_init(struct platform_device *pdev) err_free: vunmap((void *)((unsigned long)priv->addr & PAGE_MASK)); +err_add: + rproc_del(rproc); + rproc_free(rproc); + err: devres_release_group(dev, homo_core_of_init); return ret; @@ -414,12 +422,16 @@ static int homo_core_of_init(struct platform_device *pdev) static void homo_core_of_exit(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct rproc *rproc = platform_get_drvdata(pdev); + + rproc_del(rproc); + rproc_free(rproc); platform_set_drvdata(pdev, NULL); devres_release_group(dev, homo_core_of_init); } -static void homo_cluster_of_exit(struct platform_device *pdev) +static void homo_cluster_of_exit(void) { struct rproc *rproc; struct platform_device *cpdev; @@ -468,7 +480,7 @@ static int homo_cluster_of_init(struct platform_device *pdev) return 0; fail: - homo_cluster_of_exit(pdev); + homo_cluster_of_exit(); return ret; } @@ -512,10 +524,7 @@ static int homo_rproc_probe(struct platform_device *pdev) static int homo_rproc_remove(struct platform_device *pdev) { - struct rproc *rproc = platform_get_drvdata(pdev); - - rproc_del(rproc); - rproc_free(rproc); + homo_cluster_of_exit(); return 0; } -- Gitee From 3c8bcfcfade797a49152eac671f0d904e36f11aa Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 17 Jan 2025 18:53:32 +0800 Subject: [PATCH 10/11] driver: remoteproc: add explanatory comments and optimize the code Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index b46c36b011a..50d6c8a2c44 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -33,8 +33,10 @@ /* cpu0 handling interrupt */ #define RPROC_IRQ_HANDLE_CPU 0 +/* PSCI cpu_on code */ #define CPU_ON 0xc4000003 +/* stop flag use in resource table */ #define REMOTE_PROC_STOP 0x0001U /* wait for 1s */ @@ -78,7 +80,7 @@ static int homo_find_rproc_offset_irq(int rproc_irq) { int i; - for(i = 0; i < homo_rproc_num; i++) { + for (i = 0; i < homo_rproc_num; i++) { if (g_homo_rproc[i]->mapped_irq == rproc_irq) { return i; } @@ -268,7 +270,7 @@ static int homo_rproc_starting_cpu(unsigned int cpu) int i; int irq; - for(i = 0; i < homo_rproc_num; i++) { + for (i = 0; i < homo_rproc_num; i++) { irq = g_homo_rproc[i]->mapped_irq; enable_percpu_irq(irq, irq_get_trigger_type(irq)); } @@ -383,7 +385,7 @@ static int homo_core_of_init(struct platform_device *pdev) rproc_irq = irq_create_of_mapping(&oirq); if (rproc_irq <= 0) { ret = -EINVAL; - goto err; + goto err_free; } priv->mapped_irq = rproc_irq; @@ -411,13 +413,12 @@ static int homo_core_of_init(struct platform_device *pdev) rproc_del(rproc); rproc_free(rproc); -err: devres_release_group(dev, homo_core_of_init); return ret; } /* - * free the resources when init fail + * release each remote processor */ static void homo_core_of_exit(struct platform_device *pdev) { @@ -431,13 +432,16 @@ static void homo_core_of_exit(struct platform_device *pdev) devres_release_group(dev, homo_core_of_init); } +/* + * free the resources when init fail or driver remove + */ static void homo_cluster_of_exit(void) { struct rproc *rproc; struct platform_device *cpdev; int i; - for(i = 0; i < homo_rproc_num; i++) { + for (i = 0; i < homo_rproc_num; i++) { rproc = g_homo_rproc[i]->rproc; cpdev = to_platform_device(rproc->dev.parent); homo_core_of_exit(cpdev); @@ -446,6 +450,9 @@ static void homo_cluster_of_exit(void) homo_rproc_num = 0; } +/* + * Create remote processors by identifying the child nodes of homo_rproc in the dts + */ static int homo_cluster_of_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -466,8 +473,7 @@ static int homo_cluster_of_init(struct platform_device *pdev) ret = homo_core_of_init(cpdev); if (ret) { - dev_err(dev, "homo_core_of_init failed, ret = %d\n", - ret); + dev_err(dev, "homo_core_of_init failed, ret = %d\n", ret); put_device(&cpdev->dev); of_node_put(child); goto fail; @@ -493,8 +499,6 @@ static int homo_rproc_probe(struct platform_device *pdev) num_cores = of_get_available_child_count(np); - dev_info(dev, "num_cores = %d\n", num_cores); - if (num_cores > RPROC_CORE_MAX_NUM) { dev_err(dev, "core number (%d) out of range\n", num_cores); return -ENODEV; -- Gitee From 2f5aba740e588982f5f910998372b7ebce0a66ad Mon Sep 17 00:00:00 2001 From: huyuming1672 Date: Fri, 28 Feb 2025 15:20:44 +0800 Subject: [PATCH 11/11] driver: remoteproc: update adaptation and code optimization including: 1. Optimize code by segmenting the reserved memory mapping; 2. Fix bugs by correcting the improper use of 'rproc_del' and 'rproc_free'; 3. Add support for Carveout usage, incorporating the corresponding imgload, vring descriptor, and vring data buffer segments into Carveout during the prepare phase, enabling subsequent DMA allocation in the specified memory. Signed-off-by: huyuming1672 --- drivers/remoteproc/homo_remoteproc.c | 153 +++++++++++++++++++-------- 1 file changed, 109 insertions(+), 44 deletions(-) diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c index 50d6c8a2c44..e3b5104bfc6 100644 --- a/drivers/remoteproc/homo_remoteproc.c +++ b/drivers/remoteproc/homo_remoteproc.c @@ -1,8 +1,7 @@ /* * Homogeneous Remote Processor Control Driver * - * Copyright (c) 2022-2024 Phytium Technology Co., Ltd. - * Author: Shaojun Yang + * Copyright (c) 2022-2025 Phytium Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify it under the terms * of the GNU General Public License version 2 as published by the Free Software Foundation. @@ -40,7 +39,32 @@ #define REMOTE_PROC_STOP 0x0001U /* wait for 1s */ -#define HOMO_MAX_WAIT_TIME_NS (1000 * NSEC_PER_MSEC) +#define HOMO_MAX_WAIT_TIME_NS (1000 * NSEC_PER_MSEC) + +/* offset of the carveout relative to the starting address of the memory region */ +#define HOMO_IMGLOAD_OFFSET 0 +#define HOMO_VDEV_VIRING0_OFFSET 0x10200000 +#define HOMO_VDEV_VIRING1_OFFSET 0x10210000 +#define HOMO_VDEV_BUFFER_OFFSET 0x10220000 + +/* size of each carveout */ +#define HOMO_IMGLOAD_SIZE 0x10200000 +#define HOMO_VDEV_VIRING0_SIZE 0x00008000 +#define HOMO_VDEV_VIRING1_SIZE 0x00008000 +#define HOMO_VDEV_BUFFER_SIZE 0x00080000 + +#define HOMO_ADD_CARVEOUT(dev, base, size, name_fmt) \ + do { \ + struct rproc_mem_entry *mem = rproc_mem_entry_init( \ + dev, NULL, (dma_addr_t)(base), (size), (base), \ + homo_mem_alloc, homo_mem_release, \ + name_fmt); \ + if (!mem) { \ + dev_err(dev, "rproc_mem_entry_init err!\n"); \ + return -ENOMEM; \ + } \ + rproc_add_carveout(rproc, mem); \ + } while (0) /* Resource table for the homo remote processors */ struct homo_resource_table { @@ -203,16 +227,9 @@ static void homo_rproc_kick(struct rproc *rproc, int vqid) if (rproc->state == RPROC_RUNNING) gicv3_ipi_send_single(priv->irq, cpu_logical_map(priv->cpu)); - return ; + return; } -static const struct rproc_ops homo_rproc_ops = { - .start = homo_rproc_start, - .stop = homo_rproc_stop, - .kick = homo_rproc_kick, - .da_to_va = homo_rproc_da_to_va, -}; - static void __iomem *homo_ioremap_prot(phys_addr_t addr, size_t size, pgprot_t prot) { unsigned long offset, vaddr; @@ -282,19 +299,91 @@ static int homo_rproc_dying_cpu(unsigned int cpu) int i; int irq; - for(i = 0; i < homo_rproc_num; i++) { + for (i = 0; i < homo_rproc_num; i++) { irq = g_homo_rproc[i]->mapped_irq; disable_percpu_irq(irq); } return 0; } +static int homo_mem_alloc(struct rproc *rproc, struct rproc_mem_entry *mem) +{ + struct device *dev = rproc->dev.parent; + void *va; + struct homo_rproc *priv = rproc->priv; + char load_name[32]; + + va = homo_ioremap_prot(mem->dma, mem->len, PAGE_KERNEL_EXEC); + if (!va) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", + &mem->dma, mem->len); + return -ENOMEM; + } + + snprintf(load_name, sizeof(load_name), "imgload"); + if (!strcmp(mem->name, load_name)) { + priv->addr = va; + priv->phys_addr = mem->dma; + } + + dev_dbg(dev, "name: %s, ioremap: phys_addr = %016llx, addr = %llx, size = %lx\n", + mem->name, mem->dma, (u64)va, mem->len); + + /* Update memory entry va */ + mem->va = va; + + return 0; +} + +static int homo_mem_release(struct rproc *rproc, struct rproc_mem_entry *mem) +{ + vunmap(mem->va); + + return 0; +} + +static int homo_rproc_prepare(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct device_node *np = dev->of_node; + + struct device_node *np_mem; + struct resource res; + int ret; + struct homo_rproc *priv = rproc->priv; + + np_mem = of_parse_phandle(np, "memory-region", 0); + ret = of_address_to_resource(np_mem, 0, &res); + if (ret) { + dev_err(dev, "can't find memory-region for Baremetal\n"); + return -ENOMEM; + } + + priv->rsc = NULL; + + priv->phys_addr = res.start; + priv->size = resource_size(&res); + + HOMO_ADD_CARVEOUT(dev, priv->phys_addr + HOMO_IMGLOAD_OFFSET, HOMO_IMGLOAD_SIZE, "imgload"); + HOMO_ADD_CARVEOUT(dev, priv->phys_addr + HOMO_VDEV_VIRING0_OFFSET, HOMO_VDEV_VIRING0_SIZE, "vdev0vring0"); + HOMO_ADD_CARVEOUT(dev, priv->phys_addr + HOMO_VDEV_VIRING1_OFFSET, HOMO_VDEV_VIRING1_SIZE, "vdev0vring1"); + HOMO_ADD_CARVEOUT(dev, priv->phys_addr + HOMO_VDEV_BUFFER_OFFSET, HOMO_VDEV_BUFFER_SIZE, "vdev0buffer"); + + return 0; +} + +static const struct rproc_ops homo_rproc_ops = { + .prepare = homo_rproc_prepare, + .start = homo_rproc_start, + .stop = homo_rproc_stop, + .kick = homo_rproc_kick, + .da_to_va = homo_rproc_da_to_va, +}; + static int homo_core_of_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev), *p; - struct device_node *np_mem; - struct resource res; struct homo_rproc *priv; unsigned int ipi, cpu; int ret; @@ -323,25 +412,27 @@ static int homo_core_of_init(struct platform_device *pdev) priv = g_homo_rproc[homo_rproc_num] = rproc->priv; priv->rproc = rproc; + priv->rsc = NULL; + priv->addr = NULL; /* The following values can be modified through devicetree 'homo_rproc' node */ if (of_property_read_u32(np, "remote-processor", &cpu)) { dev_err(dev, "not found 'remote-processor' property\n"); ret = -EINVAL; - goto err_add; + goto err_free; } if (of_property_read_u32(np, "inter-processor-interrupt", &ipi)) { dev_err(dev, "not found 'inter-processor-interrupt' property\n"); ret = -EINVAL; - goto err_add; + goto err_free; } /* The gic-v3 driver has registered the 0-7 range of SGI interrupt for system purpose */ if (ipi < 8) { dev_err(dev, "'inter-processor-interrupt' is %d, should be between 9~15\n", ipi); ret = -EINVAL; - goto err_add; + goto err_free; } priv->cpu = cpu; @@ -349,29 +440,6 @@ static int homo_core_of_init(struct platform_device *pdev) dev_info(dev, "remote-processor = %d, inter-processor-interrupt = %d\n", cpu, ipi); - np_mem = of_parse_phandle(np, "memory-region", 0); - ret = of_address_to_resource(np_mem, 0, &res); - if (ret) { - dev_err(dev, "can't find memory-region for Baremetal\n"); - goto err_add; - } - - priv->rsc = NULL; - priv->addr = NULL; - - priv->phys_addr = res.start; - priv->size = resource_size(&res); - - /* Map physical memory region reserved for homo remote processor. */ - priv->addr = homo_ioremap_prot(priv->phys_addr, priv->size, PAGE_KERNEL_EXEC); - if (!priv->addr) { - dev_err(dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_add; - } - dev_info(dev, "ioremap: phys_addr = %016llx, addr = %llx, size = %lld\n", - priv->phys_addr, (u64)(priv->addr), priv->size); - /* Look for the interrupt parent. */ p = of_irq_find_parent(np); if (p == NULL) { @@ -407,10 +475,6 @@ static int homo_core_of_init(struct platform_device *pdev) return 0; err_free: - vunmap((void *)((unsigned long)priv->addr & PAGE_MASK)); - -err_add: - rproc_del(rproc); rproc_free(rproc); devres_release_group(dev, homo_core_of_init); @@ -551,4 +615,5 @@ module_platform_driver(homo_rproc_driver); MODULE_DESCRIPTION("Homogeneous Remote Processor Control Driver"); MODULE_AUTHOR("Shaojun Yang "); +MODULE_AUTHOR("Yuming Hu "); MODULE_LICENSE("GPL v2"); -- Gitee