Files
opensbi/lib/utils/ipi/andes_plicsw.c
Anup Patel ee92afa638 lib: sbi: Introduce IPI device rating
A platform can have multiple IPI devices (such as ACLINT MSWI,
AIA IMSIC, etc). Currently, OpenSBI rely on platform calling
the sbi_ipi_set_device() function in correct order and prefer
the first avaiable IPI device which is fragile.

Instead of the above, introduce IPI device rating and prefer
the highest rated IPI device. This further allows extending
the sbi_ipi_raw_clear() to clear all available IPI devices.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Nick Hu <nick.hu@sifive.com>
Link: https://lore.kernel.org/r/20250904052410.546818-2-apatel@ventanamicro.com
Signed-off-by: Anup Patel <anup@brainfault.org>
2025-09-16 09:56:31 +05:30

107 lines
2.6 KiB
C

/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
* Leo Yu-Chi Liang <ycliang@andestech.com>
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ipi.h>
#include <sbi_utils/ipi/andes_plicsw.h>
struct plicsw_data plicsw;
static void plicsw_ipi_send(u32 hart_index)
{
ulong pending_reg;
u32 interrupt_id, word_index, pending_bit;
u32 target_hart = sbi_hartindex_to_hartid(hart_index);
if (plicsw.hart_count <= target_hart)
ebreak();
/*
* We assign a single bit for each hart.
* Bit 0 is hardwired to 0, thus unavailable.
* Bit(X+1) indicates that IPI is sent to hartX.
*/
interrupt_id = target_hart + 1;
word_index = interrupt_id / 32;
pending_bit = interrupt_id % 32;
pending_reg = plicsw.addr + PLICSW_PENDING_BASE + word_index * 4;
/* Set target hart's mip.MSIP */
writel_relaxed(BIT(pending_bit), (void *)pending_reg);
}
static void plicsw_ipi_clear(void)
{
u32 target_hart = current_hartid();
ulong reg = plicsw.addr + PLICSW_CONTEXT_BASE + PLICSW_CONTEXT_CLAIM +
PLICSW_CONTEXT_STRIDE * target_hart;
if (plicsw.hart_count <= target_hart)
ebreak();
/* Claim */
u32 source = readl((void *)reg);
/* A successful claim will clear mip.MSIP */
/* Complete */
writel(source, (void *)reg);
}
static struct sbi_ipi_device plicsw_ipi = {
.name = "andes_plicsw",
.rating = 200,
.ipi_send = plicsw_ipi_send,
.ipi_clear = plicsw_ipi_clear
};
int plicsw_cold_ipi_init(struct plicsw_data *plicsw)
{
int rc;
u32 interrupt_id, word_index, enable_bit;
ulong enable_reg, priority_reg;
/* Setup source priority */
for (int i = 0; i < plicsw->hart_count; i++) {
priority_reg = plicsw->addr + PLICSW_PRIORITY_BASE + i * 4;
writel(1, (void *)priority_reg);
}
/*
* Setup enable for each hart, skip non-existent interrupt ID 0
* which is hardwired to 0.
*/
for (int i = 0; i < plicsw->hart_count; i++) {
interrupt_id = i + 1;
word_index = interrupt_id / 32;
enable_bit = interrupt_id % 32;
enable_reg = plicsw->addr + PLICSW_ENABLE_BASE +
PLICSW_ENABLE_STRIDE * i + 4 * word_index;
writel(BIT(enable_bit), (void *)enable_reg);
}
/* Add PLICSW region to the root domain */
rc = sbi_domain_root_add_memrange(plicsw->addr, plicsw->size,
PLICSW_REGION_ALIGN,
SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_WRITABLE);
if (rc)
return rc;
sbi_ipi_add_device(&plicsw_ipi);
return 0;
}