Message ID | 20200520064111.317605-15-seanga2@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | riscv: Add Sipeed Maix support | expand |
Hi Sean > The previous IPI code initialized the device whenever the first call was > made to a riscv_*_ipi function. This made it difficult to determine when > the IPI device was initialized. This patch introduces a new function > riscv_init_ipi. It is called once during arch_cpu_init_dm. In SPL, it is > called in spl_invoke_opensbi. Before this point, no riscv_*_ipi functions > should be called. > > Signed-off-by: Sean Anderson <seanga2 at gmail.com> > Reviewed-by: Rick Chen <rick at andestech.com> > --- > > Changes in v11: > - Initialize IPI when used by SPL > Changes in v9: > - Fix type of ret variable in riscv_ipi_init > Changes in v7: > - Split IPI clearing off into its own patch > > Changes in v6: > - Fix some formatting > - Clear IPIs before enabling interrupts instead of using a ipi_ready flag > - Only print messages on error in smp code > > Changes in v5: > - New > > arch/riscv/cpu/cpu.c | 6 ++++ > arch/riscv/include/asm/smp.h | 43 +++++++++++++++++++++++++++ > arch/riscv/lib/andes_plic.c | 34 ++++++++------------- > arch/riscv/lib/sbi_ipi.c | 5 ++++ > arch/riscv/lib/sifive_clint.c | 33 +++++++-------------- > arch/riscv/lib/smp.c | 56 ++++++++--------------------------- > common/spl/spl_opensbi.c | 5 ++++ > 7 files changed, 95 insertions(+), 87 deletions(-) > > diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c > index 5804aa8e73..d75a3f045a 100644 > --- a/arch/riscv/cpu/cpu.c > +++ b/arch/riscv/cpu/cpu.c > @@ -98,6 +98,12 @@ int arch_cpu_init_dm(void) > csr_write(CSR_SATP, 0); > } > > +#ifdef CONFIG_SMP > + ret = riscv_init_ipi(); > + if (ret) > + return ret; > +#endif > + > return 0; > } > > diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h > index 74de92ed13..1b428856b2 100644 > --- a/arch/riscv/include/asm/smp.h > +++ b/arch/riscv/include/asm/smp.h > @@ -51,4 +51,47 @@ void handle_ipi(ulong hart); > */ > int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait); > > +/** > + * riscv_init_ipi() - Initialize inter-process interrupt (IPI) driver > + * > + * Platform code must provide this function. This function is called once after > + * the cpu driver is initialized. No other riscv_*_ipi() calls will be made > + * before this function is called. > + * > + * @return 0 if OK, -ve on error > + */ > +int riscv_init_ipi(void); > + > +/** > + * riscv_send_ipi() - Send inter-processor interrupt (IPI) > + * > + * Platform code must provide this function. > + * > + * @hart: Hart ID of receiving hart > + * @return 0 if OK, -ve on error > + */ > +int riscv_send_ipi(int hart); > + > +/** > + * riscv_clear_ipi() - Clear inter-processor interrupt (IPI) > + * > + * Platform code must provide this function. > + * > + * @hart: Hart ID of hart to be cleared > + * @return 0 if OK, -ve on error > + */ > +int riscv_clear_ipi(int hart); > + > +/** > + * riscv_get_ipi() - Get status of inter-processor interrupt (IPI) > + * > + * Platform code must provide this function. > + * > + * @hart: Hart ID of hart to be checked > + * @pending: Pointer to variable with result of the check, > + * 1 if IPI is pending, 0 otherwise > + * @return 0 if OK, -ve on error > + */ > +int riscv_get_ipi(int hart, int *pending); > + > #endif > diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c > index 20529ab3eb..5cf29df670 100644 > --- a/arch/riscv/lib/andes_plic.c > +++ b/arch/riscv/lib/andes_plic.c > @@ -30,20 +30,6 @@ > #define SEND_IPI_TO_HART(hart) (0x80 >> (hart)) > > DECLARE_GLOBAL_DATA_PTR; > -static int init_plic(void); > - > -#define PLIC_BASE_GET(void) \ > - do { \ > - long *ret; \ > - \ > - if (!gd->arch.plic) { \ > - ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \ > - if (IS_ERR(ret)) \ > - return PTR_ERR(ret); \ > - gd->arch.plic = ret; \ > - init_plic(); \ > - } \ > - } while (0) > > static int enable_ipi(int hart) > { > @@ -93,13 +79,21 @@ static int init_plic(void) > return -ENODEV; > } > > +int riscv_init_ipi(void) > +{ > + long *ret = syscon_get_first_range(RISCV_SYSCON_PLIC); > + > + if (IS_ERR(ret)) > + return PTR_ERR(ret); > + gd->arch.plic = ret; > + > + return init_plic(); > +} > + > int riscv_send_ipi(int hart) > { > - unsigned int ipi; > + unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); > > - PLIC_BASE_GET(); > - > - ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); > writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic, > gd->arch.boot_hart)); > > @@ -110,8 +104,6 @@ int riscv_clear_ipi(int hart) > { > u32 source_id; > > - PLIC_BASE_GET(); > - > source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart)); > writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart)); > > @@ -120,8 +112,6 @@ int riscv_clear_ipi(int hart) > > int riscv_get_ipi(int hart, int *pending) > { > - PLIC_BASE_GET(); > - > *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic, > gd->arch.boot_hart)); > *pending = !!(*pending & SEND_IPI_TO_HART(hart)); > diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c > index abafca9e5c..d02e2b4c48 100644 > --- a/arch/riscv/lib/sbi_ipi.c > +++ b/arch/riscv/lib/sbi_ipi.c > @@ -8,6 +8,11 @@ > #include <asm/encoding.h> > #include <asm/sbi.h> > > +int riscv_init_ipi(void) > +{ > + return 0; > +} > + > int riscv_send_ipi(int hart) > { > ulong mask; > diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c > index 5e0d25720b..78fc6c868d 100644 > --- a/arch/riscv/lib/sifive_clint.c > +++ b/arch/riscv/lib/sifive_clint.c > @@ -24,22 +24,8 @@ > > DECLARE_GLOBAL_DATA_PTR; > > -#define CLINT_BASE_GET(void) \ > - do { \ > - long *ret; \ > - \ > - if (!gd->arch.clint) { \ > - ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \ > - if (IS_ERR(ret)) \ > - return PTR_ERR(ret); \ > - gd->arch.clint = ret; \ > - } \ > - } while (0) > - > int riscv_get_time(u64 *time) > { > - CLINT_BASE_GET(); > - > *time = readq((void __iomem *)MTIME_REG(gd->arch.clint)); > > return 0; > @@ -47,17 +33,24 @@ int riscv_get_time(u64 *time) > > int riscv_set_timecmp(int hart, u64 cmp) > { > - CLINT_BASE_GET(); > - > writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart)); > > return 0; > } > > +int riscv_init_ipi(void) > +{ > + long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT); > + > + if (IS_ERR(ret)) > + return PTR_ERR(ret); > + gd->arch.clint = ret; > + > + return 0; > +} > + > int riscv_send_ipi(int hart) > { > - CLINT_BASE_GET(); > - > writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); > > return 0; > @@ -65,8 +58,6 @@ int riscv_send_ipi(int hart) > > int riscv_clear_ipi(int hart) > { > - CLINT_BASE_GET(); > - > writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); > > return 0; > @@ -74,8 +65,6 @@ int riscv_clear_ipi(int hart) > > int riscv_get_ipi(int hart, int *pending) > { > - CLINT_BASE_GET(); > - > *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart)); > > return 0; > diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c > index 17adb35730..fe992eb00f 100644 > --- a/arch/riscv/lib/smp.c > +++ b/arch/riscv/lib/smp.c > @@ -12,38 +12,6 @@ > > DECLARE_GLOBAL_DATA_PTR; > > -/** > - * riscv_send_ipi() - Send inter-processor interrupt (IPI) > - * > - * Platform code must provide this function. > - * > - * @hart: Hart ID of receiving hart > - * @return 0 if OK, -ve on error > - */ > -extern int riscv_send_ipi(int hart); > - > -/** > - * riscv_clear_ipi() - Clear inter-processor interrupt (IPI) > - * > - * Platform code must provide this function. > - * > - * @hart: Hart ID of hart to be cleared > - * @return 0 if OK, -ve on error > - */ > -extern int riscv_clear_ipi(int hart); > - > -/** > - * riscv_get_ipi() - Get status of inter-processor interrupt (IPI) > - * > - * Platform code must provide this function. > - * > - * @hart: Hart ID of hart to be checked > - * @pending: Pointer to variable with result of the check, > - * 1 if IPI is pending, 0 otherwise > - * @return 0 if OK, -ve on error > - */ > -extern int riscv_get_ipi(int hart, int *pending); > - > static int send_ipi_many(struct ipi_data *ipi, int wait) > { > ofnode node, cpus; > @@ -114,7 +82,6 @@ void handle_ipi(ulong hart) > return; > > __smp_mb(); > - > smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr; > invalidate_icache_all(); > > @@ -124,7 +91,13 @@ void handle_ipi(ulong hart) > */ > ret = riscv_clear_ipi(hart); > if (ret) { > - pr_err("Cannot clear IPI of hart %ld\n", hart); > + pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret); > + return; > + } > + > + /* Sanity check */ > + if (!smp_function) { > + pr_err("smp_function is NULL on hart %ld\n", hart); > return; > } Please remove this Sanity check, https://patchwork.ozlabs.org/project/uboot/patch/20200503024637.327733-15-seanga2 at gmail.com/ Thanks, Rick > > @@ -133,14 +106,11 @@ void handle_ipi(ulong hart) > > int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait) > { > - int ret = 0; > - struct ipi_data ipi; > + struct ipi_data ipi = { > + .addr = addr, > + .arg0 = arg0, > + .arg1 = arg1, > + }; > > - ipi.addr = addr; > - ipi.arg0 = arg0; > - ipi.arg1 = arg1; > - > - ret = send_ipi_many(&ipi, wait); > - > - return ret; > + return send_ipi_many(&ipi, wait); > } > diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c > index e88136e6f3..defddac8f2 100644 > --- a/common/spl/spl_opensbi.c > +++ b/common/spl/spl_opensbi.c > @@ -79,6 +79,11 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image) > invalidate_icache_all(); > > #ifdef CONFIG_SPL_SMP > + /* Initialize the IPI before we use it */ > + ret = riscv_init_ipi(); > + if (ret) > + hang(); > + > /* > * Start OpenSBI on all secondary harts and wait for acknowledgment. > * > -- > 2.26.2 >
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index 5804aa8e73..d75a3f045a 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -98,6 +98,12 @@ int arch_cpu_init_dm(void) csr_write(CSR_SATP, 0); } +#ifdef CONFIG_SMP + ret = riscv_init_ipi(); + if (ret) + return ret; +#endif + return 0; } diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h index 74de92ed13..1b428856b2 100644 --- a/arch/riscv/include/asm/smp.h +++ b/arch/riscv/include/asm/smp.h @@ -51,4 +51,47 @@ void handle_ipi(ulong hart); */ int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait); +/** + * riscv_init_ipi() - Initialize inter-process interrupt (IPI) driver + * + * Platform code must provide this function. This function is called once after + * the cpu driver is initialized. No other riscv_*_ipi() calls will be made + * before this function is called. + * + * @return 0 if OK, -ve on error + */ +int riscv_init_ipi(void); + +/** + * riscv_send_ipi() - Send inter-processor interrupt (IPI) + * + * Platform code must provide this function. + * + * @hart: Hart ID of receiving hart + * @return 0 if OK, -ve on error + */ +int riscv_send_ipi(int hart); + +/** + * riscv_clear_ipi() - Clear inter-processor interrupt (IPI) + * + * Platform code must provide this function. + * + * @hart: Hart ID of hart to be cleared + * @return 0 if OK, -ve on error + */ +int riscv_clear_ipi(int hart); + +/** + * riscv_get_ipi() - Get status of inter-processor interrupt (IPI) + * + * Platform code must provide this function. + * + * @hart: Hart ID of hart to be checked + * @pending: Pointer to variable with result of the check, + * 1 if IPI is pending, 0 otherwise + * @return 0 if OK, -ve on error + */ +int riscv_get_ipi(int hart, int *pending); + #endif diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c index 20529ab3eb..5cf29df670 100644 --- a/arch/riscv/lib/andes_plic.c +++ b/arch/riscv/lib/andes_plic.c @@ -30,20 +30,6 @@ #define SEND_IPI_TO_HART(hart) (0x80 >> (hart)) DECLARE_GLOBAL_DATA_PTR; -static int init_plic(void); - -#define PLIC_BASE_GET(void) \ - do { \ - long *ret; \ - \ - if (!gd->arch.plic) { \ - ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \ - if (IS_ERR(ret)) \ - return PTR_ERR(ret); \ - gd->arch.plic = ret; \ - init_plic(); \ - } \ - } while (0) static int enable_ipi(int hart) { @@ -93,13 +79,21 @@ static int init_plic(void) return -ENODEV; } +int riscv_init_ipi(void) +{ + long *ret = syscon_get_first_range(RISCV_SYSCON_PLIC); + + if (IS_ERR(ret)) + return PTR_ERR(ret); + gd->arch.plic = ret; + + return init_plic(); +} + int riscv_send_ipi(int hart) { - unsigned int ipi; + unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); - PLIC_BASE_GET(); - - ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart)); @@ -110,8 +104,6 @@ int riscv_clear_ipi(int hart) { u32 source_id; - PLIC_BASE_GET(); - source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart)); writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart)); @@ -120,8 +112,6 @@ int riscv_clear_ipi(int hart) int riscv_get_ipi(int hart, int *pending) { - PLIC_BASE_GET(); - *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart)); *pending = !!(*pending & SEND_IPI_TO_HART(hart)); diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c index abafca9e5c..d02e2b4c48 100644 --- a/arch/riscv/lib/sbi_ipi.c +++ b/arch/riscv/lib/sbi_ipi.c @@ -8,6 +8,11 @@ #include <asm/encoding.h> #include <asm/sbi.h> +int riscv_init_ipi(void) +{ + return 0; +} + int riscv_send_ipi(int hart) { ulong mask; diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c index 5e0d25720b..78fc6c868d 100644 --- a/arch/riscv/lib/sifive_clint.c +++ b/arch/riscv/lib/sifive_clint.c @@ -24,22 +24,8 @@ DECLARE_GLOBAL_DATA_PTR; -#define CLINT_BASE_GET(void) \ - do { \ - long *ret; \ - \ - if (!gd->arch.clint) { \ - ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \ - if (IS_ERR(ret)) \ - return PTR_ERR(ret); \ - gd->arch.clint = ret; \ - } \ - } while (0) - int riscv_get_time(u64 *time) { - CLINT_BASE_GET(); - *time = readq((void __iomem *)MTIME_REG(gd->arch.clint)); return 0; @@ -47,17 +33,24 @@ int riscv_get_time(u64 *time) int riscv_set_timecmp(int hart, u64 cmp) { - CLINT_BASE_GET(); - writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart)); return 0; } +int riscv_init_ipi(void) +{ + long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT); + + if (IS_ERR(ret)) + return PTR_ERR(ret); + gd->arch.clint = ret; + + return 0; +} + int riscv_send_ipi(int hart) { - CLINT_BASE_GET(); - writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); return 0; @@ -65,8 +58,6 @@ int riscv_send_ipi(int hart) int riscv_clear_ipi(int hart) { - CLINT_BASE_GET(); - writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); return 0; @@ -74,8 +65,6 @@ int riscv_clear_ipi(int hart) int riscv_get_ipi(int hart, int *pending) { - CLINT_BASE_GET(); - *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart)); return 0; diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c index 17adb35730..fe992eb00f 100644 --- a/arch/riscv/lib/smp.c +++ b/arch/riscv/lib/smp.c @@ -12,38 +12,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * riscv_send_ipi() - Send inter-processor interrupt (IPI) - * - * Platform code must provide this function. - * - * @hart: Hart ID of receiving hart - * @return 0 if OK, -ve on error - */ -extern int riscv_send_ipi(int hart); - -/** - * riscv_clear_ipi() - Clear inter-processor interrupt (IPI) - * - * Platform code must provide this function. - * - * @hart: Hart ID of hart to be cleared - * @return 0 if OK, -ve on error - */ -extern int riscv_clear_ipi(int hart); - -/** - * riscv_get_ipi() - Get status of inter-processor interrupt (IPI) - * - * Platform code must provide this function. - * - * @hart: Hart ID of hart to be checked - * @pending: Pointer to variable with result of the check, - * 1 if IPI is pending, 0 otherwise - * @return 0 if OK, -ve on error - */ -extern int riscv_get_ipi(int hart, int *pending); - static int send_ipi_many(struct ipi_data *ipi, int wait) { ofnode node, cpus; @@ -114,7 +82,6 @@ void handle_ipi(ulong hart) return; __smp_mb(); - smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr; invalidate_icache_all(); @@ -124,7 +91,13 @@ void handle_ipi(ulong hart) */ ret = riscv_clear_ipi(hart); if (ret) { - pr_err("Cannot clear IPI of hart %ld\n", hart); + pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret); + return; + } + + /* Sanity check */ + if (!smp_function) { + pr_err("smp_function is NULL on hart %ld\n", hart); return; } @@ -133,14 +106,11 @@ void handle_ipi(ulong hart) int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait) { - int ret = 0; - struct ipi_data ipi; + struct ipi_data ipi = { + .addr = addr, + .arg0 = arg0, + .arg1 = arg1, + }; - ipi.addr = addr; - ipi.arg0 = arg0; - ipi.arg1 = arg1; - - ret = send_ipi_many(&ipi, wait); - - return ret; + return send_ipi_many(&ipi, wait); } diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c index e88136e6f3..defddac8f2 100644 --- a/common/spl/spl_opensbi.c +++ b/common/spl/spl_opensbi.c @@ -79,6 +79,11 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image) invalidate_icache_all(); #ifdef CONFIG_SPL_SMP + /* Initialize the IPI before we use it */ + ret = riscv_init_ipi(); + if (ret) + hang(); + /* * Start OpenSBI on all secondary harts and wait for acknowledgment. *