[PATCH v2 11/13] lib: utils/irqchip: Add APLIC initialization library
Atish Patra
atishp at atishpatra.org
Fri Feb 11 16:32:19 PST 2022
On Wed, Feb 9, 2022 at 7:05 AM Anup Patel <apatel at ventanamicro.com> wrote:
>
> We add simple APLIC initialization library which is independent of
> hardware description format (FDT or ACPI). This APLIC initialization
> library can be used by custom OpenSBI platform support to setup
> APLIC domains.
>
> Signed-off-by: Anup Patel <anup.patel at wdc.com>
> Signed-off-by: Anup Patel <apatel at ventanamicro.com>
> ---
> include/sbi_utils/irqchip/aplic.h | 47 +++++
> lib/utils/irqchip/aplic.c | 279 ++++++++++++++++++++++++++++++
> lib/utils/irqchip/objects.mk | 1 +
> 3 files changed, 327 insertions(+)
> create mode 100644 include/sbi_utils/irqchip/aplic.h
> create mode 100644 lib/utils/irqchip/aplic.c
>
> diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
> new file mode 100644
> index 0000000..82682e8
> --- /dev/null
> +++ b/include/sbi_utils/irqchip/aplic.h
> @@ -0,0 +1,47 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + * Copyright (c) 2022 Ventana Micro Systems Inc.
> + *
> + * Authors:
> + * Anup Patel <anup.patel at wdc.com>
> + */
> +
> +#ifndef __IRQCHIP_APLIC_H__
> +#define __IRQCHIP_APLIC_H__
> +
> +#include <sbi/sbi_types.h>
> +
> +#define APLIC_MAX_DELEGATE 16
> +
> +struct aplic_msicfg_data {
> + unsigned long lhxs;
> + unsigned long lhxw;
> + unsigned long hhxs;
> + unsigned long hhxw;
> + unsigned long base_addr;
> +};
> +
> +struct aplic_delegate_data {
> + u32 first_irq;
> + u32 last_irq;
> + u32 child_index;
> +};
> +
> +struct aplic_data {
> + unsigned long addr;
> + unsigned long size;
> + unsigned long num_idc;
> + unsigned long num_source;
> + bool targets_mmode;
> + bool has_msicfg_mmode;
> + struct aplic_msicfg_data msicfg_mmode;
> + bool has_msicfg_smode;
> + struct aplic_msicfg_data msicfg_smode;
> + struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
> +};
> +
> +int aplic_cold_irqchip_init(struct aplic_data *aplic);
> +
> +#endif
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> new file mode 100644
> index 0000000..0a8469b
> --- /dev/null
> +++ b/lib/utils/irqchip/aplic.c
> @@ -0,0 +1,279 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + * Copyright (c) 2022 Ventana Micro Systems Inc.
> + *
> + * Authors:
> + * Anup Patel <anup.patel at wdc.com>
> + */
> +
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi_utils/irqchip/aplic.h>
> +
> +#define APLIC_MAX_IDC (1UL << 14)
> +#define APLIC_MAX_SOURCE 1024
> +
> +#define APLIC_DOMAINCFG 0x0000
> +#define APLIC_DOMAINCFG_IE (1 << 8)
> +#define APLIC_DOMAINCFG_DM (1 << 2)
> +#define APLIC_DOMAINCFG_BE (1 << 0)
> +
> +#define APLIC_SOURCECFG_BASE 0x0004
> +#define APLIC_SOURCECFG_D (1 << 10)
> +#define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff
> +#define APLIC_SOURCECFG_SM_MASK 0x00000007
> +#define APLIC_SOURCECFG_SM_INACTIVE 0x0
> +#define APLIC_SOURCECFG_SM_DETACH 0x1
> +#define APLIC_SOURCECFG_SM_EDGE_RISE 0x4
> +#define APLIC_SOURCECFG_SM_EDGE_FALL 0x5
> +#define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6
> +#define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7
> +
> +#define APLIC_MMSICFGADDR 0x1bc0
> +#define APLIC_MMSICFGADDRH 0x1bc4
> +#define APLIC_SMSICFGADDR 0x1bc8
> +#define APLIC_SMSICFGADDRH 0x1bcc
> +
> +#define APLIC_xMSICFGADDRH_L (1UL << 31)
> +#define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f
> +#define APLIC_xMSICFGADDRH_HHXS_SHIFT 24
> +#define APLIC_xMSICFGADDRH_LHXS_MASK 0x7
> +#define APLIC_xMSICFGADDRH_LHXS_SHIFT 20
> +#define APLIC_xMSICFGADDRH_HHXW_MASK 0x7
> +#define APLIC_xMSICFGADDRH_HHXW_SHIFT 16
> +#define APLIC_xMSICFGADDRH_LHXW_MASK 0xf
> +#define APLIC_xMSICFGADDRH_LHXW_SHIFT 12
> +#define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff
> +
> +#define APLIC_xMSICFGADDR_PPN_SHIFT 12
> +
> +#define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
> + ((1UL << (__lhxs)) - 1)
> +
> +#define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
> + ((1UL << (__lhxw)) - 1)
> +#define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
> + ((__lhxs))
> +#define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
> + (APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
> + APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
> +
> +#define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
> + ((1UL << (__hhxw)) - 1)
> +#define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
> + ((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
> +#define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
> + (APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
> + APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
> +
> +#define APLIC_SETIP_BASE 0x1c00
> +#define APLIC_SETIPNUM 0x1cdc
> +
> +#define APLIC_CLRIP_BASE 0x1d00
> +#define APLIC_CLRIPNUM 0x1ddc
> +
> +#define APLIC_SETIE_BASE 0x1e00
> +#define APLIC_SETIENUM 0x1edc
> +
> +#define APLIC_CLRIE_BASE 0x1f00
> +#define APLIC_CLRIENUM 0x1fdc
> +
> +#define APLIC_SETIPNUM_LE 0x2000
> +#define APLIC_SETIPNUM_BE 0x2004
> +
> +#define APLIC_TARGET_BASE 0x3004
> +#define APLIC_TARGET_HART_IDX_SHIFT 18
> +#define APLIC_TARGET_HART_IDX_MASK 0x3fff
> +#define APLIC_TARGET_GUEST_IDX_SHIFT 12
> +#define APLIC_TARGET_GUEST_IDX_MASK 0x3f
> +#define APLIC_TARGET_IPRIO_MASK 0xff
> +#define APLIC_TARGET_EIID_MASK 0x7ff
> +
> +#define APLIC_IDC_BASE 0x4000
> +#define APLIC_IDC_SIZE 32
> +
> +#define APLIC_IDC_IDELIVERY 0x00
> +
> +#define APLIC_IDC_IFORCE 0x04
> +
> +#define APLIC_IDC_ITHRESHOLD 0x08
> +
> +#define APLIC_IDC_TOPI 0x18
> +#define APLIC_IDC_TOPI_ID_SHIFT 16
> +#define APLIC_IDC_TOPI_ID_MASK 0x3ff
> +#define APLIC_IDC_TOPI_PRIO_MASK 0xff
> +
> +#define APLIC_IDC_CLAIMI 0x1c
> +
> +#define APLIC_DEFAULT_PRIORITY 1
> +#define APLIC_DISABLE_IDELIVERY 0
> +#define APLIC_ENABLE_IDELIVERY 1
> +#define APLIC_DISABLE_ITHRESHOLD 1
> +#define APLIC_ENABLE_ITHRESHOLD 0
> +
> +static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
> + void *msicfgaddr, void *msicfgaddrH)
> +{
> + u32 val;
> + unsigned long base_ppn;
> +
> + /* Check if MSI config is already locked */
> + if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
> + return;
> +
> + /* Compute the MSI base PPN */
> + base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
> + base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
> + base_ppn &= ~APLIC_xMSICFGADDR_PPN_LHX(msicfg->lhxw, msicfg->lhxs);
> + base_ppn &= ~APLIC_xMSICFGADDR_PPN_HHX(msicfg->hhxw, msicfg->hhxs);
> +
> + /* Write the lower MSI config register */
> + writel((u32)base_ppn, msicfgaddr);
> +
> + /* Write the upper MSI config register */
> + val = (((u64)base_ppn) >> 32) &
> + APLIC_xMSICFGADDRH_BAPPN_MASK;
> + val |= (msicfg->lhxw & APLIC_xMSICFGADDRH_LHXW_MASK)
> + << APLIC_xMSICFGADDRH_LHXW_SHIFT;
> + val |= (msicfg->hhxw & APLIC_xMSICFGADDRH_HHXW_MASK)
> + << APLIC_xMSICFGADDRH_HHXW_SHIFT;
> + val |= (msicfg->lhxs & APLIC_xMSICFGADDRH_LHXS_MASK)
> + << APLIC_xMSICFGADDRH_LHXS_SHIFT;
> + val |= (msicfg->hhxs & APLIC_xMSICFGADDRH_HHXS_MASK)
> + << APLIC_xMSICFGADDRH_HHXS_SHIFT;
> + writel(val, msicfgaddrH);
> +}
> +
> +static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
> +{
> + if (APLIC_xMSICFGADDRH_LHXS_MASK < msicfg->lhxs)
> + return SBI_EINVAL;
> +
> + if (APLIC_xMSICFGADDRH_LHXW_MASK < msicfg->lhxw)
> + return SBI_EINVAL;
> +
> + if (APLIC_xMSICFGADDRH_HHXS_MASK < msicfg->hhxs)
> + return SBI_EINVAL;
> +
> + if (APLIC_xMSICFGADDRH_HHXW_MASK < msicfg->hhxw)
> + return SBI_EINVAL;
> +
> + return 0;
> +}
> +
> +int aplic_cold_irqchip_init(struct aplic_data *aplic)
> +{
> + int rc;
> + u32 i, j, tmp;
> + struct sbi_domain_memregion reg;
> + struct aplic_delegate_data *deleg;
> + u32 first_deleg_irq, last_deleg_irq;
> +
> + /* Sanity checks */
> + if (!aplic ||
> + !aplic->num_source || APLIC_MAX_SOURCE <= aplic->num_source ||
> + APLIC_MAX_IDC <= aplic->num_idc)
> + return SBI_EINVAL;
> + if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
> + rc = aplic_check_msicfg(&aplic->msicfg_mmode);
> + if (rc)
> + return rc;
> + }
> + if (aplic->targets_mmode && aplic->has_msicfg_smode) {
> + rc = aplic_check_msicfg(&aplic->msicfg_smode);
> + if (rc)
> + return rc;
> + }
> +
> + /* Set domain configuration to 0 */
> + writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
> +
> + /* Disable all interrupts */
> + for (i = 0; i <= aplic->num_source; i++)
> + writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
> + (i / 32) * sizeof(u32)));
> +
> + /* Set interrupt type and priority for all interrupts */
> + for (i = 1; i <= aplic->num_source; i++) {
> + /* Set IRQ source configuration to 0 */
> + writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> + (i - 1) * sizeof(u32)));
> + /* Set IRQ target hart index and priority to 1 */
> + writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
> + APLIC_TARGET_BASE +
> + (i - 1) * sizeof(u32)));
> + }
> +
> + /* Configure IRQ delegation */
> + first_deleg_irq = -1U;
> + last_deleg_irq = 0;
> + for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
> + deleg = &aplic->delegate[i];
> + if (!deleg->first_irq || !deleg->last_irq)
> + continue;
> + if (aplic->num_source < deleg->first_irq ||
> + aplic->num_source < deleg->last_irq)
> + continue;
> + if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
> + continue;
> + if (deleg->first_irq > deleg->last_irq) {
> + tmp = deleg->first_irq;
> + deleg->first_irq = deleg->last_irq;
> + deleg->last_irq = tmp;
> + }
> + if (deleg->first_irq < first_deleg_irq)
> + first_deleg_irq = deleg->first_irq;
> + if (last_deleg_irq < deleg->last_irq)
> + last_deleg_irq = deleg->last_irq;
> + for (j = deleg->first_irq; j <= deleg->last_irq; j++)
> + writel(APLIC_SOURCECFG_D | deleg->child_index,
> + (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> + (j - 1) * sizeof(u32)));
> + }
> +
> + /* Default initialization of IDC structures */
> + for (i = 0; i < aplic->num_idc; i++) {
> + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> + i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
> + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> + i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
> + writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
> + APLIC_IDC_BASE +
> + (i * APLIC_IDC_SIZE) +
> + APLIC_IDC_ITHRESHOLD));
> + }
> +
> + /* MSI configuration */
> + if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
> + aplic_writel_msicfg(&aplic->msicfg_mmode,
> + (void *)(aplic->addr + APLIC_MMSICFGADDR),
> + (void *)(aplic->addr + APLIC_MMSICFGADDRH));
> + }
> + if (aplic->targets_mmode && aplic->has_msicfg_smode) {
> + aplic_writel_msicfg(&aplic->msicfg_smode,
> + (void *)(aplic->addr + APLIC_SMSICFGADDR),
> + (void *)(aplic->addr + APLIC_SMSICFGADDRH));
> + }
> +
> + /*
> + * Add APLIC region to the root domain if:
> + * 1) It targets M-mode of any HART directly or via MSIs
> + * 2) All interrupts are delegated to some child APLIC
> + */
> + if (aplic->targets_mmode ||
> + ((first_deleg_irq < last_deleg_irq) &&
> + (last_deleg_irq == aplic->num_source) &&
> + (first_deleg_irq == 1))) {
> + sbi_domain_memregion_init(aplic->addr, aplic->size,
> + SBI_DOMAIN_MEMREGION_MMIO, ®);
> + rc = sbi_domain_root_add_memregion(®);
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
> diff --git a/lib/utils/irqchip/objects.mk b/lib/utils/irqchip/objects.mk
> index ae6f255..b2b3f79 100644
> --- a/lib/utils/irqchip/objects.mk
> +++ b/lib/utils/irqchip/objects.mk
> @@ -10,5 +10,6 @@
> libsbiutils-objs-y += irqchip/fdt_irqchip.o
> libsbiutils-objs-y += irqchip/fdt_irqchip_imsic.o
> libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
> +libsbiutils-objs-y += irqchip/aplic.o
> libsbiutils-objs-y += irqchip/imsic.o
> libsbiutils-objs-y += irqchip/plic.o
> --
> 2.25.1
>
LGTM.
Reviewed-by: Atish Patra <atishp at rivosinc.com>
--
Regards,
Atish
More information about the opensbi
mailing list