[PATCH 08/13] lib: utils/irqchip: Add IMSIC library

Xiang W wxjstz at 126.com
Wed Jan 19 08:08:43 PST 2022


在 2022-01-04星期二的 15:43 +0530,Anup Patel写道:
> We add simple IMSIC library which is independent of hardware
> description
> format (FDT or ACPI). This IMSIC library can be used by custom OpenSBI
> platform support to setup IMSIC for external interrupts.
> 
> Signed-off-by: Anup Patel <anup.patel at wdc.com>
> Signed-off-by: Anup Patel <apatel at ventanamicro.com>
> ---
>  include/sbi_utils/irqchip/imsic.h |  50 ++++++
>  lib/utils/irqchip/imsic.c         | 287
> ++++++++++++++++++++++++++++++
>  lib/utils/irqchip/objects.mk      |   1 +
>  3 files changed, 338 insertions(+)
>  create mode 100644 include/sbi_utils/irqchip/imsic.h
>  create mode 100644 lib/utils/irqchip/imsic.c
> 
> diff --git a/include/sbi_utils/irqchip/imsic.h
> b/include/sbi_utils/irqchip/imsic.h
> new file mode 100644
> index 0000000..cffcb5a
> --- /dev/null
> +++ b/include/sbi_utils/irqchip/imsic.h
> @@ -0,0 +1,50 @@
> +/*
> + * 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_IMSIC_H__
> +#define __IRQCHIP_IMSIC_H__
> +
> +#include <sbi/sbi_types.h>
> +
> +#define IMSIC_MMIO_PAGE_SHIFT          12
> +#define IMSIC_MMIO_PAGE_SZ             (1UL << IMSIC_MMIO_PAGE_SHIFT)
> +
> +#define IMSIC_MAX_REGS                 16
> +
> +struct imsic_regs {
> +       unsigned long addr;
> +       unsigned long size;
> +};
> +
> +struct imsic_data {
> +       bool targets_mmode;
> +       u32 guest_index_bits;
> +       u32 hart_index_bits;
> +       u32 group_index_bits;
> +       u32 group_index_shift;
> +       unsigned long num_ids;
> +       struct imsic_regs regs[IMSIC_MAX_REGS];
> +};
> +
> +int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic,
> int file);
> +
> +struct imsic_data *imsic_get_data(u32 hartid);
> +
> +int imsic_get_target_file(u32 hartid);
> +
> +void imsic_local_irqchip_init(void);
> +
> +int imsic_warm_irqchip_init(void);
> +
> +int imsic_data_check(struct imsic_data *imsic);
> +
> +int imsic_cold_irqchip_init(struct imsic_data *imsic);
> +
> +#endif
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> new file mode 100644
> index 0000000..f87321f
> --- /dev/null
> +++ b/lib/utils/irqchip/imsic.c
> @@ -0,0 +1,287 @@
> +/*
> + * 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_asm.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/riscv_encoding.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_hartmask.h>
> +#include <sbi/sbi_ipi.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_trap.h>
> +#include <sbi_utils/irqchip/imsic.h>
> +
> +#define IMSIC_MMIO_PAGE_LE             0x00
> +#define IMSIC_MMIO_PAGE_BE             0x04
> +
> +#define IMSIC_MIN_ID                   63
> +#define IMSIC_MAX_ID                   2047
> +
> +#define IMSIC_EIDELIVERY               0x70
> +
> +#define IMSIC_EITHRESHOLD              0x72
> +
> +#define IMSIC_TOPEI                    0x76
> +#define IMSIC_TOPEI_ID_SHIFT           16
> +#define IMSIC_TOPEI_ID_MASK            0x7ff
> +#define IMSIC_TOPEI_PRIO_MASK          0x7ff
> +
> +#define IMSIC_EIP0                     0x80
> +
> +#define IMSIC_EIP63                    0xbf
> +
> +#define IMSIC_EIE0                     0xc0
> +
> +#define IMSIC_EIE63                    0xff
> +
> +#define IMSIC_DISABLE_EIDELIVERY       0
> +#define IMSIC_ENABLE_EIDELIVERY        1
> +#define IMSIC_DISABLE_EITHRESHOLD      0
> +#define IMSIC_ENABLE_EITHRESHOLD       IMSIC_MAX_ID
> +
> +#define IMSIC_IPI_ID                   1
> +
> +#define imsic_csr_write(__c, __v)      \
> +do { \
> +       csr_write(CSR_MISELECT, __c); \
> +       csr_write(CSR_MIREG, __v); \
> +} while (0)
> +
> +#define imsic_csr_read(__c)    \
> +({ \
> +       unsigned long __v; \
> +       csr_write(CSR_MISELECT, __c); \
> +       __v = csr_read(CSR_MIREG); \
> +       __v; \
> +})
> +
> +static struct imsic_data *imsic_hartid2data[SBI_HARTMASK_MAX_BITS];
> +static int imsic_hartid2file[SBI_HARTMASK_MAX_BITS];
> +
> +int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic,
> int file)
> +{
> +       if (!imsic || !imsic->targets_mmode ||
> +           (SBI_HARTMASK_MAX_BITS <= hartid))
> +               return SBI_EINVAL;
> +
> +       imsic_hartid2data[hartid] = imsic;
> +       imsic_hartid2file[hartid] = file;
> +       return 0;
> +}
> +
> +struct imsic_data *imsic_get_data(u32 hartid)
> +{
> +       if (SBI_HARTMASK_MAX_BITS <= hartid)
> +               return NULL;
> +       return imsic_hartid2data[hartid];
> +}
> +
> +int imsic_get_target_file(u32 hartid)
> +{
> +       if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
> +           !imsic_hartid2data[hartid])
> +               return SBI_ENOENT;
> +       return imsic_hartid2file[hartid];
> +}
> +
> +static int imsic_external_irqfn(struct sbi_trap_regs *regs)
> +{
> +       ulong mirq;
> +
> +       while ((mirq = csr_swap(CSR_MTOPEI, 0))) {
> +               mirq = (mirq >> IMSIC_TOPEI_ID_SHIFT);
> +
> +               switch (mirq) {
> +               case IMSIC_IPI_ID:
> +                       sbi_ipi_process();
> +                       break;
Why not add a timer interrupt?
> +               default:
> +                       sbi_printf("%s: unhandled IRQ%d\n",
> +                                  __func__, (u32)mirq);
> +                       break;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static void imsic_ipi_send(u32 target_hart)
> +{
> +       unsigned long reloff;
> +       struct imsic_regs *regs;
> +       struct imsic_data *data = imsic_hartid2data[target_hart];
> +       int file = imsic_hartid2file[target_hart];
> +
> +       if (!data || !data->targets_mmode)
> +               return;
> +
> +       regs = &data->regs[0];
> +       reloff = file * (1UL << data->guest_index_bits) *
> IMSIC_MMIO_PAGE_SZ;
> +       while (regs->size && (regs->size <= reloff)) {
> +               reloff -= regs->size;
> +               regs++;
> +       }
> +
> +       if (regs->size && (reloff < regs->size))
> +               writel(IMSIC_IPI_ID,
> +                      (void *)(regs->addr + reloff +
> IMSIC_MMIO_PAGE_LE));
Using "void *" in arithmetic causes errors with -Werror=pointer-arith

Regards,
Xiang W
> +}
> +
> +static struct sbi_ipi_device imsic_ipi_device = {
> +       .name           = "aia-imsic",
> +       .ipi_send       = imsic_ipi_send
> +};
> +
> +void imsic_local_irqchip_init(void)
> +{
> +       /*
> +        * This function is expected to be called from:
> +        * 1) nascent_init() platform callback which is called
> +        *    very early on each HART in boot-up path and and
> +        *    HSM resume path.
> +        * 2) irqchip_init() platform callback which is called
> +        *    in boot-up path.
> +        */
> +
> +       /* Setup threshold to allow all enabled interrupts */
> +       imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_ENABLE_EITHRESHOLD);
> +
> +       /* Enable interrupt delivery */
> +       imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY);
> +
> +       /* Enable IPI */
> +       csr_write(CSR_MSETEIENUM, IMSIC_IPI_ID);
> +}
> +
> +int imsic_warm_irqchip_init(void)
> +{
> +       unsigned long i;
> +       struct imsic_data *imsic =
> imsic_hartid2data[current_hartid()];
> +
> +       /* Sanity checks */
> +       if (!imsic || !imsic->targets_mmode)
> +               return SBI_EINVAL;
> +
> +       /* Disable all interrupts */
> +       for (i = 1; i <= imsic->num_ids; i++)
> +               csr_write(CSR_MCLREIENUM, i);
> +
> +       /* Clear IPI */
> +       csr_write(CSR_MCLREIPNUM, IMSIC_IPI_ID);
> +
> +       /* Local IMSIC initialization */
> +       imsic_local_irqchip_init();
> +
> +       return 0;
> +}
> +
> +int imsic_data_check(struct imsic_data *imsic)
> +{
> +       u32 i, tmp;
> +       unsigned long base_addr, addr, mask;
> +
> +       /* Sanity checks */
> +       if (!imsic ||
> +           (imsic->num_ids < IMSIC_MIN_ID) ||
> +           (IMSIC_MAX_ID < imsic->num_ids))
> +               return SBI_EINVAL;
> +
> +       tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT;
> +       if (tmp < imsic->guest_index_bits)
> +               return SBI_EINVAL;
> +
> +       tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT -
> +             imsic->guest_index_bits;
> +       if (tmp < imsic->hart_index_bits)
> +               return SBI_EINVAL;
> +
> +       tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT -
> +             imsic->guest_index_bits - imsic->hart_index_bits;
> +       if (tmp < imsic->group_index_bits)
> +               return SBI_EINVAL;
> +
> +       tmp = IMSIC_MMIO_PAGE_SHIFT + imsic->guest_index_bits +
> +             imsic->hart_index_bits;
> +       if (imsic->group_index_shift < tmp)
> +               return SBI_EINVAL;
> +       tmp = imsic->group_index_bits + imsic->group_index_shift - 1;
> +       if (tmp >= BITS_PER_LONG)
> +               return SBI_EINVAL;
> +
> +       /*
> +        * Number of interrupt identities should be 1 less than
> +        * multiple of 63
> +        */
> +       if ((imsic->num_ids & IMSIC_MIN_ID) != IMSIC_MIN_ID)
> +               return SBI_EINVAL;
> +
> +       /* We should have at least one regset */
> +       if (!imsic->regs[0].size)
> +               return SBI_EINVAL;
> +
> +       /* Match patter of each regset */
> +       base_addr = imsic->regs[0].addr;
> +       base_addr &= ~((1UL << (imsic->guest_index_bits +
> +                                imsic->hart_index_bits +
> +                                IMSIC_MMIO_PAGE_SHIFT)) - 1);
> +       base_addr &= ~(((1UL << imsic->group_index_bits) - 1) <<
> +                       imsic->group_index_shift);
> +       for (i = 0; i < IMSIC_MAX_REGS && imsic->regs[i].size; i++) {
> +               mask = (1UL << imsic->guest_index_bits) *
> IMSIC_MMIO_PAGE_SZ;
> +               mask -= 1UL;
> +               if (imsic->regs[i].size & mask)
> +                       return SBI_EINVAL;
> +
> +               addr = imsic->regs[i].addr;
> +               addr &= ~((1UL << (imsic->guest_index_bits +
> +                                        imsic->hart_index_bits +
> +                                        IMSIC_MMIO_PAGE_SHIFT)) - 1);
> +               addr &= ~(((1UL << imsic->group_index_bits) - 1) <<
> +                               imsic->group_index_shift);
> +               if (base_addr != addr)
> +                       return SBI_EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +int imsic_cold_irqchip_init(struct imsic_data *imsic)
> +{
> +       int i, rc;
> +       struct sbi_domain_memregion reg;
> +
> +       /* Sanity checks */
> +       rc = imsic_data_check(imsic);
> +       if (rc)
> +               return rc;
> +
> +       /* We only initialize M-mode IMSIC */
> +       if (!imsic->targets_mmode)
> +               return SBI_EINVAL;
> +
> +       /* Setup external interrupt function for IMSIC */
> +       sbi_trap_set_external_irqfn(imsic_external_irqfn);
> +
> +       /* Add IMSIC regions to the root domain */
> +       for (i = 0; i < IMSIC_MAX_REGS && imsic->regs[i].size; i++) {
> +               sbi_domain_memregion_init(imsic->regs[i].addr,
> +                                         imsic->regs[i].size,
> +                                         SBI_DOMAIN_MEMREGION_MMIO,
> &reg);
> +               rc = sbi_domain_root_add_memregion(&reg);
> +               if (rc)
> +                       return rc;
> +       }
> +
> +       /* Register IPI device */
> +       sbi_ipi_set_device(&imsic_ipi_device);
> +
> +       return 0;
> +}
> diff --git a/lib/utils/irqchip/objects.mk
> b/lib/utils/irqchip/objects.mk
> index 934f706..76a3c94 100644
> --- a/lib/utils/irqchip/objects.mk
> +++ b/lib/utils/irqchip/objects.mk
> @@ -9,4 +9,5 @@
>  
>  libsbiutils-objs-y += irqchip/fdt_irqchip.o
>  libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
> +libsbiutils-objs-y += irqchip/imsic.o
>  libsbiutils-objs-y += irqchip/plic.o
> -- 
> 2.25.1
> 
> 





More information about the opensbi mailing list