|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 10/14] xen/riscv: implementation of aplic and imsic operations
Introduce interrupt controller descriptor for host APLIC to describe
the low-lovel hardare. It includes implementation of the following functions:
- aplic_irq_startup()
- aplic_irq_shutdown()
- aplic_irq_enable()
- aplic_irq_disable()
- aplic_irq_ack()
- aplic_host_irq_end()
- aplic_set_irq_affinity()
As APLIC is used in MSI mode it requires to enable/disable interrupts not
only for APLIC but also for IMSIC. Thereby for the purpose of
aplic_irq_{enable,disable}() it is introduced imsic_irq_{enable,disable)().
For the purpose of aplic_set_irq_affinity() aplic_get_cpu_from_mask() is
introduced to get hart id.
Also, introduce additional interrupt controller h/w operations and
host_irq_type for APLIC:
- aplic_host_irq_type
- aplic_set_irq_priority()
- aplic_set_irq_type()
Patch is based on the code from [1].
[1]
https://gitlab.com/xen-project/people/olkur/xen/-/commit/7390e2365828b83e27ead56b03114a56e3699dd5
Co-developed-by: Romain Caritey <Romain.Caritey@xxxxxxxxxxxxx>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
xen/arch/riscv/aplic.c | 169 ++++++++++++++++++++++++++++-
xen/arch/riscv/imsic.c | 63 +++++++++++
xen/arch/riscv/include/asm/aplic.h | 12 ++
xen/arch/riscv/include/asm/imsic.h | 15 +++
4 files changed, 258 insertions(+), 1 deletion(-)
diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index d1aa835c3e..4b60cb9a77 100644
--- a/xen/arch/riscv/aplic.c
+++ b/xen/arch/riscv/aplic.c
@@ -15,6 +15,7 @@
#include <xen/irq.h>
#include <xen/mm.h>
#include <xen/sections.h>
+#include <xen/spinlock.h>
#include <xen/types.h>
#include <xen/vmap.h>
@@ -110,9 +111,173 @@ static int __init aplic_init(void)
return 0;
}
-static const struct intc_hw_operations __ro_after_init aplic_ops = {
+static void aplic_set_irq_type(struct irq_desc *desc, unsigned int type)
+{
+ unsigned int irq = desc->irq - 1;
+
+ spin_lock(&aplic.lock);
+ switch(type) {
+ case IRQ_TYPE_EDGE_RISING:
+ aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_EDGE_RISE;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_EDGE_FALL;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_LEVEL_LOW;
+ break;
+ default:
+ aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_INACTIVE;
+ break;
+ }
+ spin_unlock(&aplic.lock);
+}
+
+static void aplic_set_irq_priority(struct irq_desc *desc,
+ unsigned int priority)
+{
+ /* No priority, do nothing */
+}
+
+static void aplic_irq_enable(struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ /*
+ * TODO: Currently, APLIC is supported only with MSI interrupts.
+ * If APLIC without MSI interrupts is required in the future,
+ * this function will need to be updated accordingly.
+ */
+ ASSERT(aplic.imsic_cfg->is_used);
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ spin_lock_irqsave(&aplic.lock, flags);
+
+ clear_bit(_IRQ_DISABLED, &desc->status);
+
+ /* enable interrupt in IMSIC */
+ imsic_irq_enable(desc->irq);
+
+ /* enable interrupt in APLIC */
+ aplic.regs->setienum = desc->irq;
+
+ spin_unlock_irqrestore(&aplic.lock, flags);
+}
+
+static void aplic_irq_disable(struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ /*
+ * TODO: Currently, APLIC is supported only with MSI interrupts.
+ * If APLIC without MSI interrupts is required in the future,
+ * this function will need to be updated accordingly.
+ */
+ ASSERT(aplic.imsic_cfg->is_used);
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ spin_lock_irqsave(&aplic.lock, flags);
+
+ set_bit(_IRQ_DISABLED, &desc->status);
+
+ /* disable interrupt in APLIC */
+ aplic.regs->clrienum = desc->irq;
+
+ /* disable interrupt in IMSIC */
+ imsic_irq_disable(desc->irq);
+
+ spin_unlock_irqrestore(&aplic.lock, flags);
+}
+
+static unsigned int aplic_irq_startup(struct irq_desc *desc)
+{
+ aplic_irq_enable(desc);
+
+ return 0;
+}
+
+static void aplic_irq_shutdown(struct irq_desc *desc)
+{
+ aplic_irq_disable(desc);
+}
+
+static void aplic_irq_ack(struct irq_desc *desc)
+{
+ /* nothing to do */
+}
+
+static void aplic_host_irq_end(struct irq_desc *desc)
+{
+ /* nothing to do */
+}
+
+static unsigned int aplic_get_cpu_from_mask(const cpumask_t *cpumask)
+{
+ unsigned int cpu;
+ cpumask_t possible_mask;
+
+ cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
+ cpu = cpumask_any(&possible_mask);
+
+ return cpu;
+}
+
+static void aplic_set_irq_affinity(struct irq_desc *desc, const cpumask_t
*mask)
+{
+ unsigned int cpu;
+ uint64_t group_index, base_ppn;
+ uint32_t hhxw, lhxw ,hhxs, value;
+ const struct imsic_config *imsic = aplic.imsic_cfg;
+
+ /*
+ * TODO: Currently, APLIC is supported only with MSI interrupts.
+ * If APLIC without MSI interrupts is required in the future,
+ * this function will need to be updated accordingly.
+ */
+ ASSERT(aplic.imsic_cfg->is_used);
+
+ ASSERT(!cpumask_empty(mask));
+
+ spin_lock(&aplic.lock);
+
+ cpu = cpuid_to_hartid(aplic_get_cpu_from_mask(mask));
+ hhxw = imsic->group_index_bits;
+ lhxw = imsic->hart_index_bits;
+ hhxs = imsic->group_index_shift - IMSIC_MMIO_PAGE_SHIFT * 2;
+ base_ppn = imsic->msi[cpu].base_addr >> IMSIC_MMIO_PAGE_SHIFT;
+
+ /* update hart and EEID in the target register */
+ group_index = (base_ppn >> (hhxs + 12)) & (BIT(hhxw, UL) - 1);
+ value = desc->irq;
+ value |= cpu << APLIC_TARGET_HART_IDX_SHIFT;
+ value |= group_index << (lhxw + APLIC_TARGET_HART_IDX_SHIFT) ;
+ aplic.regs->target[desc->irq - 1] = value;
+
+ spin_unlock(&aplic.lock);
+}
+
+static hw_irq_controller aplic_host_irq_type = {
+ .typename = "aplic",
+ .startup = aplic_irq_startup,
+ .shutdown = aplic_irq_shutdown,
+ .enable = aplic_irq_enable,
+ .disable = aplic_irq_disable,
+ .ack = aplic_irq_ack,
+ .end = aplic_host_irq_end,
+ .set_affinity = aplic_set_irq_affinity,
+};
+
+static const struct intc_hw_operations aplic_ops = {
.info = &aplic_info,
.init = aplic_init,
+ .host_irq_type = &aplic_host_irq_type,
+ .set_irq_priority = aplic_set_irq_priority,
+ .set_irq_type = aplic_set_irq_type,
};
static int aplic_irq_xlate(const uint32_t *intspec, unsigned int intsize,
@@ -149,6 +314,8 @@ static int __init aplic_preinit(struct dt_device_node
*node, const void *dat)
dt_irq_xlate = aplic_irq_xlate;
+ spin_lock_init(&aplic.lock);
+
register_intc_ops(&aplic_ops);
return 0;
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index 99def9af2d..8198d008ef 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -14,12 +14,68 @@
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/macros.h>
+#include <xen/spinlock.h>
#include <xen/xmalloc.h>
#include <asm/imsic.h>
static struct imsic_config imsic_cfg;
+#define imsic_csr_set(c, v) \
+do { \
+ csr_write(CSR_SISELECT, c); \
+ csr_set(CSR_SIREG, v); \
+} while (0)
+
+#define imsic_csr_clear(c, v) \
+do { \
+ csr_write(CSR_SISELECT, c); \
+ csr_clear(CSR_SIREG, v); \
+} while (0)
+
+static void imsic_local_eix_update(unsigned long base_id, unsigned long num_id,
+ bool pend, bool val)
+{
+ unsigned long i, isel, ireg;
+ unsigned long id = base_id, last_id = base_id + num_id;
+
+ while ( id < last_id )
+ {
+ isel = id / __riscv_xlen;
+ isel *= __riscv_xlen / IMSIC_EIPx_BITS;
+ isel += (pend) ? IMSIC_EIP0 : IMSIC_EIE0;
+
+ ireg = 0;
+ for ( i = id & (__riscv_xlen - 1);
+ (id < last_id) && (i < __riscv_xlen);
+ i++, id++ )
+ ireg |= (1 << i);
+
+ if ( val )
+ imsic_csr_set(isel, ireg);
+ else
+ imsic_csr_clear(isel, ireg);
+ }
+}
+
+void imsic_irq_enable(unsigned int hwirq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&imsic_cfg.lock, flags);
+ imsic_local_eix_update(hwirq, 1, false, true);
+ spin_unlock_irqrestore(&imsic_cfg.lock, flags);
+}
+
+void imsic_irq_disable(unsigned int hwirq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&imsic_cfg.lock, flags);
+ imsic_local_eix_update(hwirq, 1, false, false);
+ spin_unlock_irqrestore(&imsic_cfg.lock, flags);
+}
+
const struct imsic_config *imsic_get_config(void)
{
return &imsic_cfg;
@@ -277,6 +333,13 @@ int __init imsic_init(struct dt_device_node *node)
goto imsic_init_err;
}
+ spin_lock_init(&imsic_cfg.lock);
+
+ /* Enable local interrupt delivery */
+ imsic_ids_local_delivery(true);
+
+ imsic_cfg.is_used = true;
+
return 0;
imsic_init_err:
diff --git a/xen/arch/riscv/include/asm/aplic.h
b/xen/arch/riscv/include/asm/aplic.h
index 94b3d0b616..ce858663a9 100644
--- a/xen/arch/riscv/include/asm/aplic.h
+++ b/xen/arch/riscv/include/asm/aplic.h
@@ -18,6 +18,15 @@
#define APLIC_DOMAINCFG_IE BIT(8, UL)
#define APLIC_DOMAINCFG_DM BIT(2, UL)
+#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_TARGET_HART_IDX_SHIFT 18
+
struct aplic_regs {
uint32_t domaincfg;
uint32_t sourcecfg[1023];
@@ -70,6 +79,9 @@ struct aplic_priv {
/* registers */
volatile struct aplic_regs *regs;
+ /* lock */
+ spinlock_t lock;
+
/* imsic configuration */
const struct imsic_config *imsic_cfg;
};
diff --git a/xen/arch/riscv/include/asm/imsic.h
b/xen/arch/riscv/include/asm/imsic.h
index 126e651863..d2c0178529 100644
--- a/xen/arch/riscv/include/asm/imsic.h
+++ b/xen/arch/riscv/include/asm/imsic.h
@@ -11,6 +11,7 @@
#ifndef ASM__RISCV__IMSIC_H
#define ASM__RISCV__IMSIC_H
+#include <xen/spinlock.h>
#include <xen/types.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
@@ -19,6 +20,11 @@
#define IMSIC_MIN_ID 63
#define IMSIC_MAX_ID 2048
+#define IMSIC_EIP0 0x80
+#define IMSIC_EIPx_BITS 32
+
+#define IMSIC_EIE0 0xC0
+
struct imsic_msi {
paddr_t base_addr;
unsigned long offset;
@@ -55,6 +61,12 @@ struct imsic_config {
/* MSI */
struct imsic_msi msi[NR_CPUS];
+
+ /* a check that IMSIC is used */
+ bool is_used;
+
+ /* lock */
+ spinlock_t lock;
};
struct dt_device_node;
@@ -63,4 +75,7 @@ int imsic_init(struct dt_device_node *n);
struct imsic_config;
const struct imsic_config *imsic_get_config(void);
+void imsic_irq_enable(unsigned int hwirq);
+void imsic_irq_disable(unsigned int hwirq);
+
#endif /* ASM__RISCV__IMSIC_H */
--
2.49.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |