From: Anup Patel <apatel@ventanamicro.com>
To: opensbi@lists.infradead.org
Subject: [PATCH 08/13] lib: utils/irqchip: Add IMSIC library
Date: Tue, 4 Jan 2022 15:43:18 +0530 [thread overview]
Message-ID: <20220104101323.127564-6-apatel@ventanamicro.com> (raw)
In-Reply-To: <20220104101323.127564-1-apatel@ventanamicro.com>
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@wdc.com>
Signed-off-by: Anup Patel <apatel@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@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@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;
+ 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));
+}
+
+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, ®);
+ rc = sbi_domain_root_add_memregion(®);
+ 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
next prev parent reply other threads:[~2022-01-04 10:13 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
2022-01-04 10:13 ` [PATCH 04/13] lib: sbi: Add sbi_trap_set_external_irqfn() API Anup Patel
2022-01-04 10:13 ` [PATCH 05/13] lib: utils/irqchip: Allow multiple FDT irqchip drivers Anup Patel
2022-02-08 8:54 ` Atish Patra
2022-01-04 10:13 ` [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback Anup Patel
2022-02-08 9:07 ` Atish Patra
2022-02-09 12:07 ` Anup Patel
2022-01-04 10:13 ` [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts Anup Patel
2022-02-08 9:03 ` Atish Patra
2022-02-09 12:30 ` Anup Patel
2022-01-04 10:13 ` Anup Patel [this message]
2022-01-19 16:08 ` [PATCH 08/13] lib: utils/irqchip: Add IMSIC library Xiang W
2022-01-19 16:12 ` Jessica Clarke
2022-01-19 16:14 ` Xiang W
2022-01-04 10:13 ` [PATCH 09/13] lib: utils/irqchip: Add FDT based driver for IMSIC Anup Patel
2022-01-04 10:13 ` [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups() Anup Patel
2022-02-08 9:12 ` Atish Patra
2022-02-09 12:46 ` Anup Patel
2022-01-04 10:13 ` [PATCH 11/13] lib: utils/irqchip: Add APLIC initialization library Anup Patel
2022-01-04 10:13 ` [PATCH 12/13] lib: utils/irqchip: Add FDT based driver for APLIC Anup Patel
2022-01-04 10:13 ` [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups() Anup Patel
2022-02-08 9:13 ` Atish Patra
2022-01-19 15:57 ` [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Xiang W
2022-02-09 11:40 ` Anup Patel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220104101323.127564-6-apatel@ventanamicro.com \
--to=apatel@ventanamicro.com \
--cc=opensbi@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.