* [PATCH 04/13] lib: sbi: Add sbi_trap_set_external_irqfn() API
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 ` Anup Patel
2022-01-04 10:13 ` [PATCH 05/13] lib: utils/irqchip: Allow multiple FDT irqchip drivers Anup Patel
` (9 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
This patch adds sbi_trap_set_external_irqfn() API which can be used by
OpenSBI platform code to set a callback function for external interrupts.
The RISC-V AIA IMSIC driver will use this API to implement inter-processor
interrupts on-top-of MSIs.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi/sbi_trap.h | 2 ++
lib/sbi/sbi_trap.c | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/sbi/sbi_trap.h b/include/sbi/sbi_trap.h
index d205056..4f611fa 100644
--- a/include/sbi/sbi_trap.h
+++ b/include/sbi/sbi_trap.h
@@ -205,6 +205,8 @@ struct sbi_trap_info {
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);
+void sbi_trap_set_external_irqfn(int (*fn)(struct sbi_trap_regs *regs));
+
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
index bc8961f..faab90a 100644
--- a/lib/sbi/sbi_trap.c
+++ b/lib/sbi/sbi_trap.c
@@ -195,6 +195,27 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
return 0;
}
+static int default_irqfn(struct sbi_trap_regs *regs)
+{
+ return SBI_ENODEV;
+}
+
+static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
+
+/**
+ * Set external irq handler function
+ *
+ * This function is called by OpenSBI platform code to set a handler for
+ * external interrupts
+ *
+ * @param fn function pointer for handling external irqs
+ */
+void sbi_trap_set_external_irqfn(int (*fn)(struct sbi_trap_regs *regs))
+{
+ if (fn)
+ ext_irqfn = fn;
+}
+
static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
mcause &= ~(1UL << (__riscv_xlen - 1));
@@ -205,6 +226,8 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
case IRQ_M_SOFT:
sbi_ipi_process();
break;
+ case IRQ_M_EXT:
+ return ext_irqfn(regs);
default:
return SBI_ENOENT;
};
@@ -214,6 +237,7 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
+ int rc;
unsigned long mtopi;
while ((mtopi = csr_read(CSR_MTOPI))) {
@@ -225,6 +249,11 @@ static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
case IRQ_M_SOFT:
sbi_ipi_process();
break;
+ case IRQ_M_EXT:
+ rc = ext_irqfn(regs);
+ if (rc)
+ return rc;
+ break;
default:
return SBI_ENOENT;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 05/13] lib: utils/irqchip: Allow multiple FDT irqchip drivers
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 ` 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
` (8 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We can have multiple FDT irqchip drivers to be probed when a RISC-V
system has different types of interrupt controller in a hierarchy.
This will be certainely the case when a RISC-V system has both
RISC-V AIA IMSIC and RISC-V AIA APLIC implemented.
We extend simple FDT irqchip framework to allow multiple FDT
irqchip drivers to be used for same RISC-V platform.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
lib/utils/irqchip/fdt_irqchip.c | 37 ++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/lib/utils/irqchip/fdt_irqchip.c b/lib/utils/irqchip/fdt_irqchip.c
index 8dda661..bf6969a 100644
--- a/lib/utils/irqchip/fdt_irqchip.c
+++ b/lib/utils/irqchip/fdt_irqchip.c
@@ -18,23 +18,40 @@ static struct fdt_irqchip *irqchip_drivers[] = {
&fdt_irqchip_plic
};
-static struct fdt_irqchip *current_driver = NULL;
+#define FDT_IRQCHIP_MAX_DRIVERS 8
+
+static struct fdt_irqchip *current_drivers[FDT_IRQCHIP_MAX_DRIVERS] = {0};
+static int current_drivers_count;
void fdt_irqchip_exit(void)
{
- if (current_driver && current_driver->exit)
- current_driver->exit();
+ int i;
+
+ for (i = 0; i < current_drivers_count; i++) {
+ if (!current_drivers[i] || !current_drivers[i]->exit)
+ continue;
+ current_drivers[i]->exit();
+ }
}
static int fdt_irqchip_warm_init(void)
{
- if (current_driver && current_driver->warm_init)
- return current_driver->warm_init();
+ int i, rc;
+
+ for (i = 0; i < current_drivers_count; i++) {
+ if (!current_drivers[i] || !current_drivers[i]->warm_init)
+ continue;
+ rc = current_drivers[i]->warm_init();
+ if (rc)
+ return rc;
+ }
+
return 0;
}
static int fdt_irqchip_cold_init(void)
{
+ bool drv_added;
int pos, noff, rc;
struct fdt_irqchip *drv;
const struct fdt_match *match;
@@ -44,6 +61,7 @@ static int fdt_irqchip_cold_init(void)
drv = irqchip_drivers[pos];
noff = -1;
+ drv_added = false;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
if (drv->cold_init) {
@@ -53,10 +71,15 @@ static int fdt_irqchip_cold_init(void)
if (rc)
return rc;
}
- current_driver = drv;
+
+ if (drv_added)
+ continue;
+
+ current_drivers[current_drivers_count++] = drv;
+ drv_added = true;
}
- if (current_driver)
+ if (FDT_IRQCHIP_MAX_DRIVERS <= current_drivers_count)
break;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 05/13] lib: utils/irqchip: Allow multiple FDT irqchip drivers
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
0 siblings, 0 replies; 24+ messages in thread
From: Atish Patra @ 2022-02-08 8:54 UTC (permalink / raw)
To: opensbi
On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We can have multiple FDT irqchip drivers to be probed when a RISC-V
> system has different types of interrupt controller in a hierarchy.
>
> This will be certainely the case when a RISC-V system has both
/s/certainely/certainly
> RISC-V AIA IMSIC and RISC-V AIA APLIC implemented.
>
> We extend simple FDT irqchip framework to allow multiple FDT
> irqchip drivers to be used for same RISC-V platform.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> lib/utils/irqchip/fdt_irqchip.c | 37 ++++++++++++++++++++++++++-------
> 1 file changed, 30 insertions(+), 7 deletions(-)
>
> diff --git a/lib/utils/irqchip/fdt_irqchip.c b/lib/utils/irqchip/fdt_irqchip.c
> index 8dda661..bf6969a 100644
> --- a/lib/utils/irqchip/fdt_irqchip.c
> +++ b/lib/utils/irqchip/fdt_irqchip.c
> @@ -18,23 +18,40 @@ static struct fdt_irqchip *irqchip_drivers[] = {
> &fdt_irqchip_plic
> };
>
> -static struct fdt_irqchip *current_driver = NULL;
> +#define FDT_IRQCHIP_MAX_DRIVERS 8
> +
> +static struct fdt_irqchip *current_drivers[FDT_IRQCHIP_MAX_DRIVERS] = {0};
> +static int current_drivers_count;
>
> void fdt_irqchip_exit(void)
> {
> - if (current_driver && current_driver->exit)
> - current_driver->exit();
> + int i;
> +
> + for (i = 0; i < current_drivers_count; i++) {
> + if (!current_drivers[i] || !current_drivers[i]->exit)
> + continue;
> + current_drivers[i]->exit();
> + }
> }
>
> static int fdt_irqchip_warm_init(void)
> {
> - if (current_driver && current_driver->warm_init)
> - return current_driver->warm_init();
> + int i, rc;
> +
> + for (i = 0; i < current_drivers_count; i++) {
> + if (!current_drivers[i] || !current_drivers[i]->warm_init)
> + continue;
> + rc = current_drivers[i]->warm_init();
> + if (rc)
> + return rc;
> + }
> +
> return 0;
> }
>
> static int fdt_irqchip_cold_init(void)
> {
> + bool drv_added;
> int pos, noff, rc;
> struct fdt_irqchip *drv;
> const struct fdt_match *match;
> @@ -44,6 +61,7 @@ static int fdt_irqchip_cold_init(void)
> drv = irqchip_drivers[pos];
>
> noff = -1;
> + drv_added = false;
> while ((noff = fdt_find_match(fdt, noff,
> drv->match_table, &match)) >= 0) {
> if (drv->cold_init) {
> @@ -53,10 +71,15 @@ static int fdt_irqchip_cold_init(void)
> if (rc)
> return rc;
> }
> - current_driver = drv;
> +
> + if (drv_added)
> + continue;
> +
> + current_drivers[current_drivers_count++] = drv;
> + drv_added = true;
> }
>
> - if (current_driver)
> + if (FDT_IRQCHIP_MAX_DRIVERS <= current_drivers_count)
> break;
> }
>
> --
> 2.25.1
>
Otherwise,
Reviewed-by: Atish Patra <atishp@rivosinc.com>
--
Regards,
Atish
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback
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-01-04 10:13 ` Anup Patel
2022-02-08 9:07 ` Atish Patra
2022-01-04 10:13 ` [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts Anup Patel
` (7 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We introduce nascent_init() platform callback which will allow
platforms to do very early initialization of platform specific
per-HART CSRs and per-HART devices.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi/sbi_platform.h | 17 +++++++++++++++++
lib/sbi/sbi_init.c | 8 ++++++++
2 files changed, 25 insertions(+)
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index 4d192f2..e097785 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -64,6 +64,9 @@ enum sbi_platform_features {
/** Platform functions */
struct sbi_platform_operations {
+ /* Platform nascent initialization */
+ int (*nascent_init)(void);
+
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -299,6 +302,20 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
return FALSE;
}
+/**
+ * Nascent (very early) initialization for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->nascent_init)
+ return sbi_platform_ops(plat)->nascent_init();
+ return 0;
+}
+
/**
* Early initialization for current HART
*
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 83043c5..27d03a7 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -494,6 +494,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
+ /*
+ * Do platform specific nascent (very early) initialization so
+ * that platform can initialize platform specific per-HART CSRs
+ * or per-HART devices.
+ */
+ if (sbi_platform_nascent_init(plat))
+ sbi_hart_hang();
+
if (coldboot)
init_coldboot(scratch, hartid);
else
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback
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
0 siblings, 1 reply; 24+ messages in thread
From: Atish Patra @ 2022-02-08 9:07 UTC (permalink / raw)
To: opensbi
On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We introduce nascent_init() platform callback which will allow
> platforms to do very early initialization of platform specific
> per-HART CSRs and per-HART devices.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> include/sbi/sbi_platform.h | 17 +++++++++++++++++
> lib/sbi/sbi_init.c | 8 ++++++++
> 2 files changed, 25 insertions(+)
>
> diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
> index 4d192f2..e097785 100644
> --- a/include/sbi/sbi_platform.h
> +++ b/include/sbi/sbi_platform.h
> @@ -64,6 +64,9 @@ enum sbi_platform_features {
>
> /** Platform functions */
> struct sbi_platform_operations {
> + /* Platform nascent initialization */
> + int (*nascent_init)(void);
> +
> /** Platform early initialization */
> int (*early_init)(bool cold_boot);
> /** Platform final initialization */
> @@ -299,6 +302,20 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
> return FALSE;
> }
>
> +/**
> + * Nascent (very early) initialization for current HART
> + *
We probably need a better comment to differentiate between Nascent & early init.
Without that, platform vendors may just use this instead of early init.
> + * @param plat pointer to struct sbi_platform
> + *
> + * @return 0 on success and negative error code on failure
> + */
> +static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
> +{
> + if (plat && sbi_platform_ops(plat)->nascent_init)
> + return sbi_platform_ops(plat)->nascent_init();
> + return 0;
> +}
> +
> /**
> * Early initialization for current HART
> *
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index 83043c5..27d03a7 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -494,6 +494,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
> if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
> coldboot = TRUE;
>
> + /*
> + * Do platform specific nascent (very early) initialization so
> + * that platform can initialize platform specific per-HART CSRs
> + * or per-HART devices.
> + */
> + if (sbi_platform_nascent_init(plat))
> + sbi_hart_hang();
> +
> if (coldboot)
> init_coldboot(scratch, hartid);
> else
> --
> 2.25.1
>
Other than that, LGTM.
Reviewed-by: Atish Patra <atishp@rivosinc.com>
--
Regards,
Atish
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback
2022-02-08 9:07 ` Atish Patra
@ 2022-02-09 12:07 ` Anup Patel
0 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-02-09 12:07 UTC (permalink / raw)
To: opensbi
On Tue, Feb 8, 2022 at 2:38 PM Atish Patra <atishp@atishpatra.org> wrote:
>
> On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
> >
> > We introduce nascent_init() platform callback which will allow
> > platforms to do very early initialization of platform specific
> > per-HART CSRs and per-HART devices.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > ---
> > include/sbi/sbi_platform.h | 17 +++++++++++++++++
> > lib/sbi/sbi_init.c | 8 ++++++++
> > 2 files changed, 25 insertions(+)
> >
> > diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
> > index 4d192f2..e097785 100644
> > --- a/include/sbi/sbi_platform.h
> > +++ b/include/sbi/sbi_platform.h
> > @@ -64,6 +64,9 @@ enum sbi_platform_features {
> >
> > /** Platform functions */
> > struct sbi_platform_operations {
> > + /* Platform nascent initialization */
> > + int (*nascent_init)(void);
> > +
> > /** Platform early initialization */
> > int (*early_init)(bool cold_boot);
> > /** Platform final initialization */
> > @@ -299,6 +302,20 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
> > return FALSE;
> > }
> >
> > +/**
> > + * Nascent (very early) initialization for current HART
> > + *
>
> We probably need a better comment to differentiate between Nascent & early init.
> Without that, platform vendors may just use this instead of early init.
Okay, I will add more details in the comment here.
Regards,
Anup
>
> > + * @param plat pointer to struct sbi_platform
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
> > +{
> > + if (plat && sbi_platform_ops(plat)->nascent_init)
> > + return sbi_platform_ops(plat)->nascent_init();
> > + return 0;
> > +}
> > +
> > /**
> > * Early initialization for current HART
> > *
> > diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> > index 83043c5..27d03a7 100644
> > --- a/lib/sbi/sbi_init.c
> > +++ b/lib/sbi/sbi_init.c
> > @@ -494,6 +494,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
> > if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
> > coldboot = TRUE;
> >
> > + /*
> > + * Do platform specific nascent (very early) initialization so
> > + * that platform can initialize platform specific per-HART CSRs
> > + * or per-HART devices.
> > + */
> > + if (sbi_platform_nascent_init(plat))
> > + sbi_hart_hang();
> > +
> > if (coldboot)
> > init_coldboot(scratch, hartid);
> > else
> > --
> > 2.25.1
> >
>
> Other than that, LGTM.
>
> Reviewed-by: Atish Patra <atishp@rivosinc.com>
>
> --
> Regards,
> Atish
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (2 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-02-08 9:03 ` Atish Patra
2022-01-04 10:13 ` [PATCH 08/13] lib: utils/irqchip: Add IMSIC library Anup Patel
` (6 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We can have IPIs based on external interrupts provided by devices
such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
places in generic library.
Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
lib/sbi/sbi_hsm.c | 4 ++--
lib/sbi/sbi_init.c | 9 ++++++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index ecd2e45..c4d2c6d 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
- /* Set MSIE bit to receive IPI */
- csr_set(CSR_MIE, MIP_MSIP);
+ /* Set MSIE and MEIE bits to receive IPI */
+ csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 27d03a7..6876eb2 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -165,8 +165,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
- /* Set MSIE bit to receive IPI */
- csr_set(CSR_MIE, MIP_MSIP);
+ /* Set MSIE and MEIE bits to receive IPI */
+ csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -182,7 +182,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
do {
wfi();
cmip = csr_read(CSR_MIP);
- } while (!(cmip & MIP_MSIP));
+ } while (!(cmip & (MIP_MSIP | MIP_MEIP)));
};
/* Acquire coldboot lock */
@@ -276,6 +276,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
__func__, rc);
sbi_hart_hang();
}
+ csr_set(CSR_MIE, MIP_MEIP);
rc = sbi_ipi_init(scratch, TRUE);
if (rc) {
@@ -376,6 +377,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
rc = sbi_platform_irqchip_init(plat, FALSE);
if (rc)
sbi_hart_hang();
+ csr_set(CSR_MIE, MIP_MEIP);
rc = sbi_ipi_init(scratch, FALSE);
if (rc)
@@ -550,6 +552,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_ipi_exit(scratch);
+ csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
sbi_platform_final_exit(plat);
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
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
0 siblings, 1 reply; 24+ messages in thread
From: Atish Patra @ 2022-02-08 9:03 UTC (permalink / raw)
To: opensbi
On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We can have IPIs based on external interrupts provided by devices
> such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
> places in generic library.
>
> Signed-off-by: Anup Patel <anup@brainfault.org>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> lib/sbi/sbi_hsm.c | 4 ++--
> lib/sbi/sbi_init.c | 9 ++++++---
> 2 files changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index ecd2e45..c4d2c6d 100644
> --- a/lib/sbi/sbi_hsm.c
> +++ b/lib/sbi/sbi_hsm.c
> @@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
> /* Save MIE CSR */
> saved_mie = csr_read(CSR_MIE);
>
> - /* Set MSIE bit to receive IPI */
> - csr_set(CSR_MIE, MIP_MSIP);
> + /* Set MSIE and MEIE bits to receive IPI */
> + csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
>
> /* Wait for hart_add call*/
> while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index 27d03a7..6876eb2 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -165,8 +165,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
> /* Save MIE CSR */
> saved_mie = csr_read(CSR_MIE);
>
> - /* Set MSIE bit to receive IPI */
> - csr_set(CSR_MIE, MIP_MSIP);
> + /* Set MSIE and MEIE bits to receive IPI */
> + csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
>
> /* Acquire coldboot lock */
> spin_lock(&coldboot_lock);
> @@ -182,7 +182,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
> do {
> wfi();
> cmip = csr_read(CSR_MIP);
> - } while (!(cmip & MIP_MSIP));
> + } while (!(cmip & (MIP_MSIP | MIP_MEIP)));
> };
>
> /* Acquire coldboot lock */
> @@ -276,6 +276,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
> __func__, rc);
> sbi_hart_hang();
> }
> + csr_set(CSR_MIE, MIP_MEIP);
>
This is only required for IPIs with IMSIC devices.
Why not do it inside sbi_ipi_init along with MIP_MSIP set ?
> rc = sbi_ipi_init(scratch, TRUE);
> if (rc) {
> @@ -376,6 +377,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
> rc = sbi_platform_irqchip_init(plat, FALSE);
> if (rc)
> sbi_hart_hang();
> + csr_set(CSR_MIE, MIP_MEIP);
>
> rc = sbi_ipi_init(scratch, FALSE);
> if (rc)
> @@ -550,6 +552,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
>
> sbi_ipi_exit(scratch);
>
> + csr_clear(CSR_MIE, MIP_MEIP);
> sbi_platform_irqchip_exit(plat);
>
> sbi_platform_final_exit(plat);
> --
> 2.25.1
>
--
Regards,
Atish
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
2022-02-08 9:03 ` Atish Patra
@ 2022-02-09 12:30 ` Anup Patel
0 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-02-09 12:30 UTC (permalink / raw)
To: opensbi
On Tue, Feb 8, 2022 at 2:33 PM Atish Patra <atishp@atishpatra.org> wrote:
>
> On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
> >
> > We can have IPIs based on external interrupts provided by devices
> > such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
> > places in generic library.
> >
> > Signed-off-by: Anup Patel <anup@brainfault.org>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > ---
> > lib/sbi/sbi_hsm.c | 4 ++--
> > lib/sbi/sbi_init.c | 9 ++++++---
> > 2 files changed, 8 insertions(+), 5 deletions(-)
> >
> > diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> > index ecd2e45..c4d2c6d 100644
> > --- a/lib/sbi/sbi_hsm.c
> > +++ b/lib/sbi/sbi_hsm.c
> > @@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
> > /* Save MIE CSR */
> > saved_mie = csr_read(CSR_MIE);
> >
> > - /* Set MSIE bit to receive IPI */
> > - csr_set(CSR_MIE, MIP_MSIP);
> > + /* Set MSIE and MEIE bits to receive IPI */
> > + csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
> >
> > /* Wait for hart_add call*/
> > while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
> > diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> > index 27d03a7..6876eb2 100644
> > --- a/lib/sbi/sbi_init.c
> > +++ b/lib/sbi/sbi_init.c
> > @@ -165,8 +165,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
> > /* Save MIE CSR */
> > saved_mie = csr_read(CSR_MIE);
> >
> > - /* Set MSIE bit to receive IPI */
> > - csr_set(CSR_MIE, MIP_MSIP);
> > + /* Set MSIE and MEIE bits to receive IPI */
> > + csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
> >
> > /* Acquire coldboot lock */
> > spin_lock(&coldboot_lock);
> > @@ -182,7 +182,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
> > do {
> > wfi();
> > cmip = csr_read(CSR_MIP);
> > - } while (!(cmip & MIP_MSIP));
> > + } while (!(cmip & (MIP_MSIP | MIP_MEIP)));
> > };
> >
> > /* Acquire coldboot lock */
> > @@ -276,6 +276,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
> > __func__, rc);
> > sbi_hart_hang();
> > }
> > + csr_set(CSR_MIE, MIP_MEIP);
> >
>
> This is only required for IPIs with IMSIC devices.
> Why not do it inside sbi_ipi_init along with MIP_MSIP set ?
Setting mie.MEIP does not fit in sbi_ipi_init() because in-future
we might have a simple external interrupt handling framework in
lib/sbi itself which can call sbi_platform_irqchip_init() and also
set mie.MSIP bit.
For now, let mie.MSIP bit setting be in lib/sbi/sbi_init.c. This will
keep reminding us to move it in proper place.
Regards,
Anup
>
> > rc = sbi_ipi_init(scratch, TRUE);
> > if (rc) {
> > @@ -376,6 +377,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
> > rc = sbi_platform_irqchip_init(plat, FALSE);
> > if (rc)
> > sbi_hart_hang();
> > + csr_set(CSR_MIE, MIP_MEIP);
> >
> > rc = sbi_ipi_init(scratch, FALSE);
> > if (rc)
> > @@ -550,6 +552,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
> >
> > sbi_ipi_exit(scratch);
> >
> > + csr_clear(CSR_MIE, MIP_MEIP);
> > sbi_platform_irqchip_exit(plat);
> >
> > sbi_platform_final_exit(plat);
> > --
> > 2.25.1
> >
>
>
> --
> Regards,
> Atish
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 08/13] lib: utils/irqchip: Add IMSIC library
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (3 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-01-19 16:08 ` Xiang W
2022-01-04 10:13 ` [PATCH 09/13] lib: utils/irqchip: Add FDT based driver for IMSIC Anup Patel
` (5 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
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
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 08/13] lib: utils/irqchip: Add IMSIC library
2022-01-04 10:13 ` [PATCH 08/13] lib: utils/irqchip: Add IMSIC library Anup Patel
@ 2022-01-19 16:08 ` Xiang W
2022-01-19 16:12 ` Jessica Clarke
2022-01-19 16:14 ` Xiang W
0 siblings, 2 replies; 24+ messages in thread
From: Xiang W @ 2022-01-19 16:08 UTC (permalink / raw)
To: opensbi
? 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@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;
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,
> ®);
> +???????????????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
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 08/13] lib: utils/irqchip: Add IMSIC library
2022-01-19 16:08 ` Xiang W
@ 2022-01-19 16:12 ` Jessica Clarke
2022-01-19 16:14 ` Xiang W
1 sibling, 0 replies; 24+ messages in thread
From: Jessica Clarke @ 2022-01-19 16:12 UTC (permalink / raw)
To: opensbi
On 19 Jan 2022, at 16:08, Xiang W <wxjstz@126.com> wrote:
>
> ? 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@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;
> 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
The cast is outside the parentheses, the arithmetic happens first.
Jess
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 08/13] lib: utils/irqchip: Add IMSIC library
2022-01-19 16:08 ` Xiang W
2022-01-19 16:12 ` Jessica Clarke
@ 2022-01-19 16:14 ` Xiang W
1 sibling, 0 replies; 24+ messages in thread
From: Xiang W @ 2022-01-19 16:14 UTC (permalink / raw)
To: opensbi
? 2022-01-20???? 00:08 +0800?Xiang W???
> ? 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@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;
> 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
>
Sorry, I didn't realize that the type of regs->addr is unsigned long
> 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,
> > ®);
> > +???????????????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
> >
> >
>
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 09/13] lib: utils/irqchip: Add FDT based driver for IMSIC
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (4 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 08/13] lib: utils/irqchip: Add IMSIC library Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-01-04 10:13 ` [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups() Anup Patel
` (4 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We add simple FDT irqchip driver for IMSIC so that generic platform
(and other FDT based platforms) can utilize common IMIC library.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/fdt/fdt_helper.h | 6 ++
lib/utils/fdt/fdt_helper.c | 103 +++++++++++++++++++++++++
lib/utils/irqchip/fdt_irqchip.c | 2 +
lib/utils/irqchip/fdt_irqchip_imsic.c | 106 ++++++++++++++++++++++++++
lib/utils/irqchip/objects.mk | 1 +
platform/generic/platform.c | 12 +++
6 files changed, 230 insertions(+)
create mode 100644 lib/utils/irqchip/fdt_irqchip_imsic.c
diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 24fee7a..4c8d29e 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -68,6 +68,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
+struct imsic_data;
+
+bool fdt_check_imsic_mlevel(void *fdt);
+
+int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
+
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 5bf4021..e2782b6 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -13,6 +13,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
#define DEFAULT_UART_FREQ 0
@@ -465,6 +466,108 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
+bool fdt_check_imsic_mlevel(void *fdt)
+{
+ const fdt32_t *val;
+ int i, len, noff = 0;
+
+ if (!fdt)
+ return false;
+
+ while ((noff = fdt_node_offset_by_compatible(fdt, noff,
+ "riscv,imsics")) >= 0) {
+ val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
+ if (val && len > sizeof(fdt32_t)) {
+ len = len / sizeof(fdt32_t);
+ for (i = 0; i < len; i += 2) {
+ if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
+{
+ const fdt32_t *val;
+ struct imsic_regs *regs;
+ uint64_t reg_addr, reg_size;
+ int i, rc, len, nr_parent_irqs;
+
+ if (nodeoff < 0 || !imsic || !fdt)
+ return SBI_ENODEV;
+
+ imsic->targets_mmode = false;
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
+ if (val && len > sizeof(fdt32_t)) {
+ len = len / sizeof(fdt32_t);
+ nr_parent_irqs = len / 2;
+ for (i = 0; i < len; i += 2) {
+ if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
+ imsic->targets_mmode = true;
+ break;
+ }
+ }
+ } else
+ return SBI_EINVAL;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
+ if (val && len > 0)
+ imsic->guest_index_bits = fdt32_to_cpu(*val);
+ else
+ imsic->guest_index_bits = 0;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
+ if (val && len > 0) {
+ imsic->hart_index_bits = fdt32_to_cpu(*val);
+ } else {
+ imsic->hart_index_bits = __fls(nr_parent_irqs);
+ if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
+ imsic->hart_index_bits++;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
+ if (val && len > 0)
+ imsic->group_index_bits = fdt32_to_cpu(*val);
+ else
+ imsic->group_index_bits = 0;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
+ if (val && len > 0)
+ imsic->group_index_shift = fdt32_to_cpu(*val);
+ else
+ imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
+ if (val && len > 0)
+ imsic->num_ids = fdt32_to_cpu(*val);
+ else
+ return SBI_EINVAL;
+
+ for (i = 0; i < IMSIC_MAX_REGS; i++) {
+ regs = &imsic->regs[i];
+ regs->addr = 0;
+ regs->size = 0;
+ }
+
+ for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
+ regs = &imsic->regs[i];
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, i,
+ ®_addr, ®_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ break;
+ regs->addr = reg_addr;
+ regs->size = reg_size;
+ };
+ if (!imsic->regs[0].size)
+ return SBI_EINVAL;
+
+ return 0;
+}
+
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
{
int len, rc;
diff --git a/lib/utils/irqchip/fdt_irqchip.c b/lib/utils/irqchip/fdt_irqchip.c
index bf6969a..cf64a2e 100644
--- a/lib/utils/irqchip/fdt_irqchip.c
+++ b/lib/utils/irqchip/fdt_irqchip.c
@@ -12,9 +12,11 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
+extern struct fdt_irqchip fdt_irqchip_imsic;
extern struct fdt_irqchip fdt_irqchip_plic;
static struct fdt_irqchip *irqchip_drivers[] = {
+ &fdt_irqchip_imsic,
&fdt_irqchip_plic
};
diff --git a/lib/utils/irqchip/fdt_irqchip_imsic.c b/lib/utils/irqchip/fdt_irqchip_imsic.c
new file mode 100644
index 0000000..b6962be
--- /dev/null
+++ b/lib/utils/irqchip/fdt_irqchip_imsic.c
@@ -0,0 +1,106 @@
+/*
+ * 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 <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/imsic.h>
+
+#define IMSIC_MAX_NR 16
+
+static unsigned long imsic_count = 0;
+static struct imsic_data imsic[IMSIC_MAX_NR];
+
+static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff,
+ struct imsic_data *id)
+{
+ const fdt32_t *val;
+ u32 phandle, hwirq, hartid;
+ int i, err, count, cpu_offset, cpu_intc_offset;
+
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
+ if (!val || count < sizeof(fdt32_t))
+ return SBI_EINVAL;
+ count = count / sizeof(fdt32_t);
+
+ for (i = 0; i < count; i += 2) {
+ phandle = fdt32_to_cpu(val[i]);
+ hwirq = fdt32_to_cpu(val[i + 1]);
+
+ cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ return SBI_EINVAL;
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ return SBI_EINVAL;
+
+ switch (hwirq) {
+ case IRQ_M_EXT:
+ err = imsic_map_hartid_to_data(hartid, id, i / 2);
+ if (err)
+ return err;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int irqchip_imsic_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct imsic_data *id;
+
+ if (IMSIC_MAX_NR <= imsic_count)
+ return SBI_ENOSPC;
+ id = &imsic[imsic_count];
+
+ rc = fdt_parse_imsic_node(fdt, nodeoff, id);
+ if (rc)
+ return rc;
+ if (!id->targets_mmode)
+ return 0;
+
+ rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id);
+ if (rc)
+ return rc;
+
+ rc = imsic_cold_irqchip_init(id);
+ if (rc)
+ return rc;
+
+ imsic_count++;
+
+ return 0;
+}
+
+static const struct fdt_match irqchip_imsic_match[] = {
+ { .compatible = "riscv,imsics" },
+ { },
+};
+
+struct fdt_irqchip fdt_irqchip_imsic = {
+ .match_table = irqchip_imsic_match,
+ .cold_init = irqchip_imsic_cold_init,
+ .warm_init = imsic_warm_irqchip_init,
+};
diff --git a/lib/utils/irqchip/objects.mk b/lib/utils/irqchip/objects.mk
index 76a3c94..ae6f255 100644
--- a/lib/utils/irqchip/objects.mk
+++ b/lib/utils/irqchip/objects.mk
@@ -8,6 +8,7 @@
#
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/imsic.o
libsbiutils-objs-y += irqchip/plic.o
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index bc6e761..8a4fb70 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -18,6 +18,7 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/ipi/fdt_ipi.h>
@@ -56,6 +57,7 @@ static void fw_platform_lookup_special(void *fdt, int root_offset)
}
extern struct sbi_platform platform;
+static bool platform_has_mlevel_imsic = false;
static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
/*
@@ -110,6 +112,8 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
platform.hart_count = hart_count;
+ platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt);
+
/* Return original FDT pointer */
return arg1;
@@ -118,6 +122,13 @@ fail:
wfi();
}
+static int generic_nascent_init(void)
+{
+ if (platform_has_mlevel_imsic)
+ imsic_local_irqchip_init();
+ return 0;
+}
+
static int generic_early_init(bool cold_boot)
{
if (!generic_plat || !generic_plat->early_init)
@@ -210,6 +221,7 @@ static uint64_t generic_pmu_xlate_to_mhpmevent(uint32_t event_idx,
}
const struct sbi_platform_operations platform_ops = {
+ .nascent_init = generic_nascent_init,
.early_init = generic_early_init,
.final_init = generic_final_init,
.early_exit = generic_early_exit,
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (5 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 09/13] lib: utils/irqchip: Add FDT based driver for IMSIC Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-02-08 9:12 ` Atish Patra
2022-01-04 10:13 ` [PATCH 11/13] lib: utils/irqchip: Add APLIC initialization library Anup Patel
` (3 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We should disable IMSIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/fdt/fdt_fixup.h | 17 ++++++++++++++--
lib/utils/fdt/fdt_fixup.c | 32 +++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
index c38e5d9..77575bb 100644
--- a/include/sbi_utils/fdt/fdt_fixup.h
+++ b/include/sbi_utils/fdt/fdt_fixup.h
@@ -21,6 +21,18 @@
*/
void fdt_cpu_fixup(void *fdt);
+/**
+ * Fix up the IMSIC nodes in the device tree
+ *
+ * This routine disables IMSIC nodes which are not accessible to the next
+ * booting stage based on currently assigned domain.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ */
+void fdt_imsic_fixup(void *fdt);
+
/**
* Fix up the PLIC node in the device tree
*
@@ -64,8 +76,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
- * It fixes up the PLIC node and the reserved memory node in the device tree
- * by calling the corresponding helper routines to accomplish the task.
+ * It fixes up the PLIC node, IMSIC nodes, and the reserved memory node in
+ * the device tree by calling the corresponding helper routines to accomplish
+ * the task.
*
* It is recommended that platform codes call this helper in their final_init()
*
diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
index ac01ba3..c2460b8 100644
--- a/lib/utils/fdt/fdt_fixup.c
+++ b/lib/utils/fdt/fdt_fixup.c
@@ -52,6 +52,34 @@ void fdt_cpu_fixup(void *fdt)
}
}
+static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
+{
+ int rc;
+ uint64_t reg_addr, reg_size;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return;
+
+ if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
+ SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
+ rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
+ if (rc < 0)
+ return;
+ fdt_setprop_string(fdt, nodeoff, "status", "disabled");
+ }
+}
+
+void fdt_imsic_fixup(void *fdt)
+{
+ int noff = 0;
+
+ while ((noff = fdt_node_offset_by_compatible(fdt, noff,
+ "riscv,imsics")) >= 0)
+ fdt_domain_based_fixup_one(fdt, noff);
+}
+
void fdt_plic_fixup(void *fdt)
{
u32 *cells;
@@ -261,10 +289,10 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
+ fdt_imsic_fixup(fdt);
+
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
fdt_pmu_fixup(fdt);
}
-
-
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
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
0 siblings, 1 reply; 24+ messages in thread
From: Atish Patra @ 2022-02-08 9:12 UTC (permalink / raw)
To: opensbi
On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We should disable IMSIC DT nodes in fdt_fixups() which are not
> accessible to the next booting stage based on currently assigned
> domain.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> include/sbi_utils/fdt/fdt_fixup.h | 17 ++++++++++++++--
> lib/utils/fdt/fdt_fixup.c | 32 +++++++++++++++++++++++++++++--
> 2 files changed, 45 insertions(+), 4 deletions(-)
>
> diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
> index c38e5d9..77575bb 100644
> --- a/include/sbi_utils/fdt/fdt_fixup.h
> +++ b/include/sbi_utils/fdt/fdt_fixup.h
> @@ -21,6 +21,18 @@
> */
> void fdt_cpu_fixup(void *fdt);
>
> +/**
> + * Fix up the IMSIC nodes in the device tree
> + *
> + * This routine disables IMSIC nodes which are not accessible to the next
> + * booting stage based on currently assigned domain.
> + *
> + * It is recommended that platform codes call this helper in their final_init()
> + *
> + * @param fdt: device tree blob
> + */
> +void fdt_imsic_fixup(void *fdt);
> +
> /**
> * Fix up the PLIC node in the device tree
> *
> @@ -64,8 +76,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
> * General device tree fix-up
> *
> * This routine do all required device tree fix-ups for a typical platform.
> - * It fixes up the PLIC node and the reserved memory node in the device tree
> - * by calling the corresponding helper routines to accomplish the task.
> + * It fixes up the PLIC node, IMSIC nodes, and the reserved memory node in
> + * the device tree by calling the corresponding helper routines to accomplish
> + * the task.
> *
> * It is recommended that platform codes call this helper in their final_init()
> *
> diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
> index ac01ba3..c2460b8 100644
> --- a/lib/utils/fdt/fdt_fixup.c
> +++ b/lib/utils/fdt/fdt_fixup.c
> @@ -52,6 +52,34 @@ void fdt_cpu_fixup(void *fdt)
> }
> }
>
> +static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
> +{
> + int rc;
> + uint64_t reg_addr, reg_size;
> + struct sbi_domain *dom = sbi_domain_thishart_ptr();
> +
> + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
> + if (rc < 0 || !reg_addr || !reg_size)
> + return;
> +
> + if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
> + SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
> + rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
> + if (rc < 0)
> + return;
> + fdt_setprop_string(fdt, nodeoff, "status", "disabled");
> + }
> +}
> +
This should be in a separate patch as it is a generic function and
doesn't match the commit text.
> +void fdt_imsic_fixup(void *fdt)
> +{
> + int noff = 0;
> +
> + while ((noff = fdt_node_offset_by_compatible(fdt, noff,
> + "riscv,imsics")) >= 0)
> + fdt_domain_based_fixup_one(fdt, noff);
> +}
> +
> void fdt_plic_fixup(void *fdt)
> {
> u32 *cells;
> @@ -261,10 +289,10 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
>
> void fdt_fixups(void *fdt)
> {
> + fdt_imsic_fixup(fdt);
> +
> fdt_plic_fixup(fdt);
>
> fdt_reserved_memory_fixup(fdt);
> fdt_pmu_fixup(fdt);
> }
> -
> -
> --
> 2.25.1
>
Otherwise, LGTM.
Reviewed-by: Atish Patra <atishp@rivosinc.com>
--
Regards,
Atish
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
2022-02-08 9:12 ` Atish Patra
@ 2022-02-09 12:46 ` Anup Patel
0 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-02-09 12:46 UTC (permalink / raw)
To: opensbi
On Tue, Feb 8, 2022 at 2:43 PM Atish Patra <atishp@atishpatra.org> wrote:
>
> On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
> >
> > We should disable IMSIC DT nodes in fdt_fixups() which are not
> > accessible to the next booting stage based on currently assigned
> > domain.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > ---
> > include/sbi_utils/fdt/fdt_fixup.h | 17 ++++++++++++++--
> > lib/utils/fdt/fdt_fixup.c | 32 +++++++++++++++++++++++++++++--
> > 2 files changed, 45 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
> > index c38e5d9..77575bb 100644
> > --- a/include/sbi_utils/fdt/fdt_fixup.h
> > +++ b/include/sbi_utils/fdt/fdt_fixup.h
> > @@ -21,6 +21,18 @@
> > */
> > void fdt_cpu_fixup(void *fdt);
> >
> > +/**
> > + * Fix up the IMSIC nodes in the device tree
> > + *
> > + * This routine disables IMSIC nodes which are not accessible to the next
> > + * booting stage based on currently assigned domain.
> > + *
> > + * It is recommended that platform codes call this helper in their final_init()
> > + *
> > + * @param fdt: device tree blob
> > + */
> > +void fdt_imsic_fixup(void *fdt);
> > +
> > /**
> > * Fix up the PLIC node in the device tree
> > *
> > @@ -64,8 +76,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
> > * General device tree fix-up
> > *
> > * This routine do all required device tree fix-ups for a typical platform.
> > - * It fixes up the PLIC node and the reserved memory node in the device tree
> > - * by calling the corresponding helper routines to accomplish the task.
> > + * It fixes up the PLIC node, IMSIC nodes, and the reserved memory node in
> > + * the device tree by calling the corresponding helper routines to accomplish
> > + * the task.
> > *
> > * It is recommended that platform codes call this helper in their final_init()
> > *
> > diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
> > index ac01ba3..c2460b8 100644
> > --- a/lib/utils/fdt/fdt_fixup.c
> > +++ b/lib/utils/fdt/fdt_fixup.c
> > @@ -52,6 +52,34 @@ void fdt_cpu_fixup(void *fdt)
> > }
> > }
> >
> > +static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
> > +{
> > + int rc;
> > + uint64_t reg_addr, reg_size;
> > + struct sbi_domain *dom = sbi_domain_thishart_ptr();
> > +
> > + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
> > + if (rc < 0 || !reg_addr || !reg_size)
> > + return;
> > +
> > + if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
> > + SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
> > + rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
> > + if (rc < 0)
> > + return;
> > + fdt_setprop_string(fdt, nodeoff, "status", "disabled");
> > + }
> > +}
> > +
>
> This should be in a separate patch as it is a generic function and
> doesn't match the commit text.
This is a static function only used here. If it were a public function
then I would have moved it to a separate patch.
Regards,
Anup
>
> > +void fdt_imsic_fixup(void *fdt)
> > +{
> > + int noff = 0;
> > +
> > + while ((noff = fdt_node_offset_by_compatible(fdt, noff,
> > + "riscv,imsics")) >= 0)
> > + fdt_domain_based_fixup_one(fdt, noff);
> > +}
> > +
> > void fdt_plic_fixup(void *fdt)
> > {
> > u32 *cells;
> > @@ -261,10 +289,10 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
> >
> > void fdt_fixups(void *fdt)
> > {
> > + fdt_imsic_fixup(fdt);
> > +
> > fdt_plic_fixup(fdt);
> >
> > fdt_reserved_memory_fixup(fdt);
> > fdt_pmu_fixup(fdt);
> > }
> > -
> > -
> > --
> > 2.25.1
> >
>
> Otherwise, LGTM.
>
> Reviewed-by: Atish Patra <atishp@rivosinc.com>
>
>
> --
> Regards,
> Atish
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 11/13] lib: utils/irqchip: Add APLIC initialization library
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (6 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups() Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-01-04 10:13 ` [PATCH 12/13] lib: utils/irqchip: Add FDT based driver for APLIC Anup Patel
` (2 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
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@wdc.com>
Signed-off-by: Anup Patel <apatel@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@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..b8741c8
--- /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@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 0
+#define APLIC_DISABLE_IDELIVERY 0
+#define APLIC_ENABLE_IDELIVERY 1
+#define APLIC_DISABLE_ITHRESHOLD APLIC_DEFAULT_PRIORITY
+#define APLIC_ENABLE_ITHRESHOLD (APLIC_DEFAULT_PRIORITY + 1)
+
+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
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 12/13] lib: utils/irqchip: Add FDT based driver for APLIC
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (7 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 11/13] lib: utils/irqchip: Add APLIC initialization library Anup Patel
@ 2022-01-04 10:13 ` Anup Patel
2022-01-04 10:13 ` [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups() Anup Patel
2022-01-19 15:57 ` [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Xiang W
10 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We add simple FDT irqchip driver for APLIC so that generic platform (and
other FDT based platforms) can utilize common APLIC initialization library.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/fdt/fdt_helper.h | 4 +
lib/utils/fdt/fdt_helper.c | 159 ++++++++++++++++++++++++++
lib/utils/irqchip/fdt_irqchip.c | 2 +
lib/utils/irqchip/fdt_irqchip_aplic.c | 56 +++++++++
lib/utils/irqchip/objects.mk | 1 +
5 files changed, 222 insertions(+)
create mode 100644 lib/utils/irqchip/fdt_irqchip_aplic.c
diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 4c8d29e..1232b26 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -68,6 +68,10 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
+struct aplic_data;
+
+int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
+
struct imsic_data;
bool fdt_check_imsic_mlevel(void *fdt);
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index e2782b6..2f5ebc8 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -13,6 +13,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
@@ -466,6 +467,164 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
+int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
+{
+ bool child_found;
+ const fdt32_t *val;
+ const fdt32_t *del;
+ struct imsic_data imsic;
+ int i, j, d, dcnt, len, noff, rc;
+ uint64_t reg_addr, reg_size;
+ struct aplic_delegate_data *deleg;
+
+ if (nodeoff < 0 || !aplic || !fdt)
+ return SBI_ENODEV;
+ memset(aplic, 0, sizeof(*aplic));
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ aplic->addr = reg_addr;
+ aplic->size = reg_size;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
+ if (len > 0)
+ aplic->num_source = fdt32_to_cpu(*val);
+
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
+ if (val && len > sizeof(fdt32_t)) {
+ len = len / sizeof(fdt32_t);
+ for (i = 0; i < len; i += 2) {
+ if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
+ aplic->targets_mmode = true;
+ break;
+ }
+ }
+ aplic->num_idc = len / 2;
+ goto aplic_msi_parent_done;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
+ if (val && len >= sizeof(fdt32_t)) {
+ noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
+ if (noff < 0)
+ return noff;
+
+ rc = fdt_parse_imsic_node(fdt, noff, &imsic);
+ if (rc)
+ return rc;
+
+ rc = imsic_data_check(&imsic);
+ if (rc)
+ return rc;
+
+ aplic->targets_mmode = imsic.targets_mmode;
+
+ if (imsic.targets_mmode) {
+ aplic->has_msicfg_mmode = true;
+ aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
+ aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
+ aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
+ aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
+ if (aplic->msicfg_mmode.hhxs <
+ (2 * IMSIC_MMIO_PAGE_SHIFT))
+ return SBI_EINVAL;
+ aplic->msicfg_mmode.hhxs -= 24;
+ aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
+ } else {
+ goto aplic_msi_parent_done;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
+ if (!val || len < sizeof(fdt32_t))
+ goto aplic_msi_parent_done;
+
+ noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
+ if (noff < 0)
+ return noff;
+
+ val = fdt_getprop(fdt, noff, "msi-parent", &len);
+ if (!val || len < sizeof(fdt32_t))
+ goto aplic_msi_parent_done;
+
+ noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
+ if (noff < 0)
+ return noff;
+
+ rc = fdt_parse_imsic_node(fdt, noff, &imsic);
+ if (rc)
+ return rc;
+
+ rc = imsic_data_check(&imsic);
+ if (rc)
+ return rc;
+
+ if (!imsic.targets_mmode) {
+ aplic->has_msicfg_smode = true;
+ aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
+ aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
+ aplic->msicfg_smode.hhxw = imsic.group_index_bits;
+ aplic->msicfg_smode.hhxs = imsic.group_index_shift;
+ if (aplic->msicfg_smode.hhxs <
+ (2 * IMSIC_MMIO_PAGE_SHIFT))
+ return SBI_EINVAL;
+ aplic->msicfg_smode.hhxs -= 24;
+ aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
+ }
+ }
+aplic_msi_parent_done:
+
+ for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
+ deleg = &aplic->delegate[d];
+ deleg->first_irq = 0;
+ deleg->last_irq = 0;
+ deleg->child_index = 0;
+ }
+
+ del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
+ if (!del || len < (3 * sizeof(fdt32_t)))
+ goto skip_delegate_parse;
+ d = 0;
+ dcnt = len / sizeof(fdt32_t);
+ for (i = 0; i < dcnt; i += 3) {
+ if (d >= APLIC_MAX_DELEGATE)
+ break;
+ deleg = &aplic->delegate[d];
+
+ deleg->first_irq = fdt32_to_cpu(del[i + 1]);
+ deleg->last_irq = fdt32_to_cpu(del[i + 2]);
+ deleg->child_index = 0;
+
+ child_found = false;
+ val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
+ if (!val || len < sizeof(fdt32_t)) {
+ deleg->first_irq = 0;
+ deleg->last_irq = 0;
+ deleg->child_index = 0;
+ continue;
+ }
+ len = len / sizeof(fdt32_t);
+ for (j = 0; j < len; j++) {
+ if (del[i] != val[j])
+ continue;
+ deleg->child_index = j;
+ child_found = true;
+ break;
+ }
+
+ if (child_found) {
+ d++;
+ } else {
+ deleg->first_irq = 0;
+ deleg->last_irq = 0;
+ deleg->child_index = 0;
+ }
+ }
+skip_delegate_parse:
+
+ return 0;
+}
+
bool fdt_check_imsic_mlevel(void *fdt)
{
const fdt32_t *val;
diff --git a/lib/utils/irqchip/fdt_irqchip.c b/lib/utils/irqchip/fdt_irqchip.c
index cf64a2e..6007755 100644
--- a/lib/utils/irqchip/fdt_irqchip.c
+++ b/lib/utils/irqchip/fdt_irqchip.c
@@ -12,10 +12,12 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
+extern struct fdt_irqchip fdt_irqchip_aplic;
extern struct fdt_irqchip fdt_irqchip_imsic;
extern struct fdt_irqchip fdt_irqchip_plic;
static struct fdt_irqchip *irqchip_drivers[] = {
+ &fdt_irqchip_aplic,
&fdt_irqchip_imsic,
&fdt_irqchip_plic
};
diff --git a/lib/utils/irqchip/fdt_irqchip_aplic.c b/lib/utils/irqchip/fdt_irqchip_aplic.c
new file mode 100644
index 0000000..965f023
--- /dev/null
+++ b/lib/utils/irqchip/fdt_irqchip_aplic.c
@@ -0,0 +1,56 @@
+/*
+ * 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 <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/aplic.h>
+
+#define APLIC_MAX_NR 16
+
+static unsigned long aplic_count = 0;
+static struct aplic_data aplic[APLIC_MAX_NR];
+
+static int irqchip_aplic_warm_init(void)
+{
+ /* Nothing to do here. */
+ return 0;
+}
+
+static int irqchip_aplic_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct aplic_data *pd;
+
+ if (APLIC_MAX_NR <= aplic_count)
+ return SBI_ENOSPC;
+ pd = &aplic[aplic_count++];
+
+ rc = fdt_parse_aplic_node(fdt, nodeoff, pd);
+ if (rc)
+ return rc;
+
+ return aplic_cold_irqchip_init(pd);
+}
+
+static const struct fdt_match irqchip_aplic_match[] = {
+ { .compatible = "riscv,aplic" },
+ { },
+};
+
+struct fdt_irqchip fdt_irqchip_aplic = {
+ .match_table = irqchip_aplic_match,
+ .cold_init = irqchip_aplic_cold_init,
+ .warm_init = irqchip_aplic_warm_init,
+ .exit = NULL,
+};
diff --git a/lib/utils/irqchip/objects.mk b/lib/utils/irqchip/objects.mk
index b2b3f79..fad4344 100644
--- a/lib/utils/irqchip/objects.mk
+++ b/lib/utils/irqchip/objects.mk
@@ -8,6 +8,7 @@
#
libsbiutils-objs-y += irqchip/fdt_irqchip.o
+libsbiutils-objs-y += irqchip/fdt_irqchip_aplic.o
libsbiutils-objs-y += irqchip/fdt_irqchip_imsic.o
libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
libsbiutils-objs-y += irqchip/aplic.o
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups()
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (8 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 12/13] lib: utils/irqchip: Add FDT based driver for APLIC Anup Patel
@ 2022-01-04 10:13 ` 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
10 siblings, 1 reply; 24+ messages in thread
From: Anup Patel @ 2022-01-04 10:13 UTC (permalink / raw)
To: opensbi
We should disable APLIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/fdt/fdt_fixup.h | 18 +++++++++++++++---
lib/utils/fdt/fdt_fixup.c | 11 +++++++++++
2 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
index 77575bb..fb076ba 100644
--- a/include/sbi_utils/fdt/fdt_fixup.h
+++ b/include/sbi_utils/fdt/fdt_fixup.h
@@ -21,6 +21,18 @@
*/
void fdt_cpu_fixup(void *fdt);
+/**
+ * Fix up the APLIC nodes in the device tree
+ *
+ * This routine disables APLIC nodes which are not accessible to the next
+ * booting stage based on currently assigned domain.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ */
+void fdt_aplic_fixup(void *fdt);
+
/**
* Fix up the IMSIC nodes in the device tree
*
@@ -76,9 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
- * It fixes up the PLIC node, IMSIC nodes, and the reserved memory node in
- * the device tree by calling the corresponding helper routines to accomplish
- * the task.
+ * It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
+ * memory node in the device tree by calling the corresponding helper
+ * routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*
diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
index c2460b8..a80bd82 100644
--- a/lib/utils/fdt/fdt_fixup.c
+++ b/lib/utils/fdt/fdt_fixup.c
@@ -71,6 +71,15 @@ static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
}
}
+void fdt_aplic_fixup(void *fdt)
+{
+ int noff = 0;
+
+ while ((noff = fdt_node_offset_by_compatible(fdt, noff,
+ "riscv,aplic")) >= 0)
+ fdt_domain_based_fixup_one(fdt, noff);
+}
+
void fdt_imsic_fixup(void *fdt)
{
int noff = 0;
@@ -289,6 +298,8 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
+ fdt_aplic_fixup(fdt);
+
fdt_imsic_fixup(fdt);
fdt_plic_fixup(fdt);
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups()
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
0 siblings, 0 replies; 24+ messages in thread
From: Atish Patra @ 2022-02-08 9:13 UTC (permalink / raw)
To: opensbi
On Tue, Jan 4, 2022 at 2:13 AM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We should disable APLIC DT nodes in fdt_fixups() which are not
> accessible to the next booting stage based on currently assigned
> domain.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> include/sbi_utils/fdt/fdt_fixup.h | 18 +++++++++++++++---
> lib/utils/fdt/fdt_fixup.c | 11 +++++++++++
> 2 files changed, 26 insertions(+), 3 deletions(-)
>
> diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
> index 77575bb..fb076ba 100644
> --- a/include/sbi_utils/fdt/fdt_fixup.h
> +++ b/include/sbi_utils/fdt/fdt_fixup.h
> @@ -21,6 +21,18 @@
> */
> void fdt_cpu_fixup(void *fdt);
>
> +/**
> + * Fix up the APLIC nodes in the device tree
> + *
> + * This routine disables APLIC nodes which are not accessible to the next
> + * booting stage based on currently assigned domain.
> + *
> + * It is recommended that platform codes call this helper in their final_init()
> + *
> + * @param fdt: device tree blob
> + */
> +void fdt_aplic_fixup(void *fdt);
> +
> /**
> * Fix up the IMSIC nodes in the device tree
> *
> @@ -76,9 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
> * General device tree fix-up
> *
> * This routine do all required device tree fix-ups for a typical platform.
> - * It fixes up the PLIC node, IMSIC nodes, and the reserved memory node in
> - * the device tree by calling the corresponding helper routines to accomplish
> - * the task.
> + * It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
> + * memory node in the device tree by calling the corresponding helper
> + * routines to accomplish the task.
> *
> * It is recommended that platform codes call this helper in their final_init()
> *
> diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
> index c2460b8..a80bd82 100644
> --- a/lib/utils/fdt/fdt_fixup.c
> +++ b/lib/utils/fdt/fdt_fixup.c
> @@ -71,6 +71,15 @@ static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
> }
> }
>
> +void fdt_aplic_fixup(void *fdt)
> +{
> + int noff = 0;
> +
> + while ((noff = fdt_node_offset_by_compatible(fdt, noff,
> + "riscv,aplic")) >= 0)
> + fdt_domain_based_fixup_one(fdt, noff);
> +}
> +
> void fdt_imsic_fixup(void *fdt)
> {
> int noff = 0;
> @@ -289,6 +298,8 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
>
> void fdt_fixups(void *fdt)
> {
> + fdt_aplic_fixup(fdt);
> +
> fdt_imsic_fixup(fdt);
>
> fdt_plic_fixup(fdt);
> --
> 2.25.1
>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
--
Regards,
Atish
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
` (9 preceding siblings ...)
2022-01-04 10:13 ` [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups() Anup Patel
@ 2022-01-19 15:57 ` Xiang W
2022-02-09 11:40 ` Anup Patel
10 siblings, 1 reply; 24+ messages in thread
From: Xiang W @ 2022-01-19 15:57 UTC (permalink / raw)
To: opensbi
? 2022-01-04???? 15:43 +0530?Anup Patel???
> We should use AIA CSRs to process local interrupts whenever AIA
> is available.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
The interrupts triggered by AIA should all be external interrupts. For
platforms that support AIA, mcause should only receive external
interrupts, and then handle timers and software interrupts in external
interrupts. We shouldn't need two versions of sbi_trap_irq
Regards,
Xiang W
> ---
> ?lib/sbi/sbi_trap.c | 57 +++++++++++++++++++++++++++++++++++++--------
> -
> ?1 file changed, 46 insertions(+), 11 deletions(-)
>
> diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
> index 8d20e04..bc8961f 100644
> --- a/lib/sbi/sbi_trap.c
> +++ b/lib/sbi/sbi_trap.c
> @@ -195,6 +195,44 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
> ????????return 0;
> ?}
> ?
> +static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong
> mcause)
> +{
> +???????mcause &= ~(1UL << (__riscv_xlen - 1));
> +???????switch (mcause) {
> +???????case IRQ_M_TIMER:
> +???????????????sbi_timer_process();
> +???????????????break;
> +???????case IRQ_M_SOFT:
> +???????????????sbi_ipi_process();
> +???????????????break;
> +???????default:
> +???????????????return SBI_ENOENT;
> +???????};
> +
> +???????return 0;
> +}
> +
> +static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
> +{
> +???????unsigned long mtopi;
> +
> +???????while ((mtopi = csr_read(CSR_MTOPI))) {
> +???????????????mtopi = mtopi >> TOPI_IID_SHIFT;
> +???????????????switch (mtopi) {
> +???????????????case IRQ_M_TIMER:
> +???????????????????????sbi_timer_process();
> +???????????????????????break;
> +???????????????case IRQ_M_SOFT:
> +???????????????????????sbi_ipi_process();
> +???????????????????????break;
> +???????????????default:
> +???????????????????????return SBI_ENOENT;
> +???????????????}
> +???????}
> +
> +???????return 0;
> +}
> +
> ?/**
> ? * Handle trap/interrupt
> ? *
> @@ -225,18 +263,15 @@ struct sbi_trap_regs *sbi_trap_handler(struct
> sbi_trap_regs *regs)
> ????????}
> ?
> ????????if (mcause & (1UL << (__riscv_xlen - 1))) {
> -???????????????mcause &= ~(1UL << (__riscv_xlen - 1));
> -???????????????switch (mcause) {
> -???????????????case IRQ_M_TIMER:
> -???????????????????????sbi_timer_process();
> -???????????????????????break;
> -???????????????case IRQ_M_SOFT:
> -???????????????????????sbi_ipi_process();
> -???????????????????????break;
> -???????????????default:
> -???????????????????????msg = "unhandled external interrupt";
> +???????????????if (sbi_hart_has_feature(sbi_scratch_thishart_ptr(),
> +??????????????????????????????????????? SBI_HART_HAS_AIA))
> +???????????????????????rc = sbi_trap_aia_irq(regs, mcause);
> +???????????????else
> +???????????????????????rc = sbi_trap_nonaia_irq(regs, mcause);
> +???????????????if (rc) {
> +???????????????????????msg = "unhandled local interrupt";
> ????????????????????????goto trap_error;
> -???????????????};
> +???????????????}
> ????????????????return regs;
> ????????}
> ?
> --
> 2.25.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available
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
0 siblings, 0 replies; 24+ messages in thread
From: Anup Patel @ 2022-02-09 11:40 UTC (permalink / raw)
To: opensbi
On Wed, Jan 19, 2022 at 9:27 PM Xiang W <wxjstz@126.com> wrote:
>
> ? 2022-01-04???? 15:43 +0530?Anup Patel???
> > We should use AIA CSRs to process local interrupts whenever AIA
> > is available.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> The interrupts triggered by AIA should all be external interrupts. For
> platforms that support AIA, mcause should only receive external
> interrupts, and then handle timers and software interrupts in external
> interrupts. We shouldn't need two versions of sbi_trap_irq
The way external interrupts are to be handled using AIA local interrupt
CSRs is different from traditional (i.e. non-AIA) way of handling external
interrupt. With AIA local interrupt CSRs, we can handle multiple local
interrupts (using MTOPI) in the same interrupt handling context whereas
without AIA we can only handle one local interrupt (using MCAUSE) in
the same interrupt handle context.
Also with AIA IMSIC, the IPIs can be handles via IMSIC as external
interrupts and platforms don't need to provide special M-mode IPI device
when AIA IMSIC is present.
The AIA IMSIC does not provide any alternative way for timer interrupts
so these have to be handled as local interrupts.
Regards,
Anup
>
> Regards,
> Xiang W
> > ---
> > lib/sbi/sbi_trap.c | 57 +++++++++++++++++++++++++++++++++++++--------
> > -
> > 1 file changed, 46 insertions(+), 11 deletions(-)
> >
> > diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
> > index 8d20e04..bc8961f 100644
> > --- a/lib/sbi/sbi_trap.c
> > +++ b/lib/sbi/sbi_trap.c
> > @@ -195,6 +195,44 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
> > return 0;
> > }
> >
> > +static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong
> > mcause)
> > +{
> > + mcause &= ~(1UL << (__riscv_xlen - 1));
> > + switch (mcause) {
> > + case IRQ_M_TIMER:
> > + sbi_timer_process();
> > + break;
> > + case IRQ_M_SOFT:
> > + sbi_ipi_process();
> > + break;
> > + default:
> > + return SBI_ENOENT;
> > + };
> > +
> > + return 0;
> > +}
> > +
> > +static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
> > +{
> > + unsigned long mtopi;
> > +
> > + while ((mtopi = csr_read(CSR_MTOPI))) {
> > + mtopi = mtopi >> TOPI_IID_SHIFT;
> > + switch (mtopi) {
> > + case IRQ_M_TIMER:
> > + sbi_timer_process();
> > + break;
> > + case IRQ_M_SOFT:
> > + sbi_ipi_process();
> > + break;
> > + default:
> > + return SBI_ENOENT;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > /**
> > * Handle trap/interrupt
> > *
> > @@ -225,18 +263,15 @@ struct sbi_trap_regs *sbi_trap_handler(struct
> > sbi_trap_regs *regs)
> > }
> >
> > if (mcause & (1UL << (__riscv_xlen - 1))) {
> > - mcause &= ~(1UL << (__riscv_xlen - 1));
> > - switch (mcause) {
> > - case IRQ_M_TIMER:
> > - sbi_timer_process();
> > - break;
> > - case IRQ_M_SOFT:
> > - sbi_ipi_process();
> > - break;
> > - default:
> > - msg = "unhandled external interrupt";
> > + if (sbi_hart_has_feature(sbi_scratch_thishart_ptr(),
> > + SBI_HART_HAS_AIA))
> > + rc = sbi_trap_aia_irq(regs, mcause);
> > + else
> > + rc = sbi_trap_nonaia_irq(regs, mcause);
> > + if (rc) {
> > + msg = "unhandled local interrupt";
> > goto trap_error;
> > - };
> > + }
> > return regs;
> > }
> >
> > --
> > 2.25.1
> >
> >
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread