diff options
author | Yu Chien Peter Lin <peterlin@andestech.com> | 2023-11-16 20:46:12 +0800 |
---|---|---|
committer | Leo Yu-Chi Liang <ycliang@andestech.com> | 2023-12-06 16:05:39 +0800 |
commit | d1b24a61404a2073034dc53a10c64434d706d998 (patch) | |
tree | d42609575bbca8c5d1f708a42051fcf459b62d53 | |
parent | 3980baa41144b979da784cc83d9d3cc9126ca8c6 (diff) |
riscv: andes: Fix enable register settings of PLICSW
On 32-core platform, hart31 gets stuck at secondary_hart_loop
as the corresponding enable bit is not set in enable_ipi().
We should program the next word (0x2f84) which is assigned
as the enable register of hart31. It should be done in the same
way when we invoke riscv_send_ipi() to trigger software interrupt
on hart31.
The following diagram shows the enable bits of the fixed PLICSW
scheme.
Pending regs: 0x1000 x---0---0---0---0------0---0
Pending hart ID: 0 1 2 3 ... 30 31
Interrupt ID: 0 1 2 3 4 ... 31 32
| | | | | | |
Enable regs: 0x2000 x---1---0---0---0-...--0---0---> hart0
| | | | | | |
0x2080 x---0---1---0---0-...--0---0---> hart1
| | | | | | |
0x2100 x---0---0---1---0-...--0---0---> hart2
| | | | | | |
0x2180 x---0---0---0---1-...--0---0---> hart3
. . . . . . .
. . . . . . .
. . . . . . .
0x2f00 x---0---0---0---0-...--1---0---> hart30
| | | | | | |
0x2f80 x---0---0---0---0-...--0---1---> hart31
<-------- word 0 -------><--- word 1 --->
This patch includes some cleanups to macros/functions.
Fixes: ebf11273220a ("riscv: andes: Rearrange Andes PLICSW to single-bit-per-hart strategy")
Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Randolph <randolph@andestech.com>
-rw-r--r-- | arch/riscv/lib/andes_plicsw.c | 33 |
1 files changed, 15 insertions, 18 deletions
diff --git a/arch/riscv/lib/andes_plicsw.c b/arch/riscv/lib/andes_plicsw.c index 6a63661312a..c09e5c69bc3 100644 --- a/arch/riscv/lib/andes_plicsw.c +++ b/arch/riscv/lib/andes_plicsw.c @@ -21,41 +21,36 @@ #include <linux/err.h> /* pending register */ -#define PENDING_REG(base) ((ulong)(base) + 0x1000) +#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + 4 * (((hart) + 1) / 32)) /* enable register */ -#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80) +#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80 + 4 * (((hart) + 1) / 32)) /* claim register */ #define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000) /* priority register */ #define PRIORITY_REG(base) ((ulong)(base) + PLICSW_PRIORITY_BASE) /* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */ -#define FIRST_AVAILABLE_BIT 0x2 -#define SEND_IPI_TO_HART(hart) (FIRST_AVAILABLE_BIT << (hart)) #define PLICSW_PRIORITY_BASE 0x4 -#define PLICSW_INTERRUPT_PER_HART 0x1 DECLARE_GLOBAL_DATA_PTR; static int enable_ipi(int hart) { - unsigned int en; + u32 enable_bit = (hart + 1) % 32; - en = FIRST_AVAILABLE_BIT << hart; - writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart)); + writel(BIT(enable_bit), (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart)); return 0; } static void init_priority_ipi(int hart_num) { - uint32_t *priority = (void *)PRIORITY_REG(gd->arch.plicsw); + u32 *priority = (void *)PRIORITY_REG(gd->arch.plicsw); - for (int i = 0; i < hart_num * PLICSW_INTERRUPT_PER_HART; i++) { - writel(1, &priority[i]); - } + for (int i = 0; i < hart_num; i++) + writel(1, &priority[i]); - return; + return; } int riscv_init_ipi(void) @@ -104,9 +99,10 @@ int riscv_init_ipi(void) int riscv_send_ipi(int hart) { - unsigned int ipi = SEND_IPI_TO_HART(hart); + u32 interrupt_id = hart + 1; + u32 pending_bit = interrupt_id % 32; - writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw)); + writel(BIT(pending_bit), (void __iomem *)PENDING_REG(gd->arch.plicsw, hart)); return 0; } @@ -123,10 +119,11 @@ int riscv_clear_ipi(int hart) int riscv_get_ipi(int hart, int *pending) { - unsigned int ipi = SEND_IPI_TO_HART(hart); + u32 interrupt_id = hart + 1; + u32 pending_bit = interrupt_id % 32; - *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw)); - *pending = !!(*pending & ipi); + *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw, hart)); + *pending = !!(*pending & BIT(pending_bit)); return 0; } |