Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 5 Feb 2025 09:34:41 GMT
From:      Ruslan Bukin <br@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: ae65d59d4b8c - main - riscv vmm: various fixes in APLIC.
Message-ID:  <202502050934.5159YfUu025609@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by br:

URL: https://cgit.FreeBSD.org/src/commit/?id=ae65d59d4b8c227ac27b58497b9295e09fa9a179

commit ae65d59d4b8c227ac27b58497b9295e09fa9a179
Author:     Ruslan Bukin <br@FreeBSD.org>
AuthorDate: 2025-02-05 09:25:37 +0000
Commit:     Ruslan Bukin <br@FreeBSD.org>
CommitDate: 2025-02-05 09:30:11 +0000

    riscv vmm: various fixes in APLIC.
    
    - Implement Level-sensitive interrupts
    - Disable up to 32 interrupts by a single query (CLRIE register handling)
    - Implement reading from DOMAINCFG
    
    All of this needed for Linux guest.
    
    Differential Revision:  https://reviews.freebsd.org/D48808
---
 sys/riscv/vmm/vmm_aplic.c | 85 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/sys/riscv/vmm/vmm_aplic.c b/sys/riscv/vmm/vmm_aplic.c
index 60da6b4a27fb..4df41f2de1a5 100644
--- a/sys/riscv/vmm/vmm_aplic.c
+++ b/sys/riscv/vmm/vmm_aplic.c
@@ -70,9 +70,13 @@ MALLOC_DEFINE(M_APLIC, "RISC-V VMM APLIC", "RISC-V AIA APLIC");
 /* If D == 1. */
 #define	 SOURCECFG_CHILD_INDEX_S	(0)
 #define	 SOURCECFG_CHILD_INDEX_M	(0x3ff << SOURCECFG_CHILD_INDEX_S)
+#define	APLIC_SETIP		0x1c00
 #define	APLIC_SETIPNUM		0x1cdc
+#define	APLIC_CLRIP		0x1d00
 #define	APLIC_CLRIPNUM		0x1ddc
+#define	APLIC_SETIE		0x1e00
 #define	APLIC_SETIENUM		0x1edc
+#define	APLIC_CLRIE		0x1f00
 #define	APLIC_CLRIENUM		0x1fdc
 #define	APLIC_GENMSI		0x3000
 #define	APLIC_TARGET(x)		(0x3004 + ((x) - 1) * 4)
@@ -96,6 +100,7 @@ struct aplic_irq {
 	uint32_t state;
 #define	APLIC_IRQ_STATE_PENDING	(1 << 0)
 #define	APLIC_IRQ_STATE_ENABLED	(1 << 1)
+#define	APLIC_IRQ_STATE_INPUT	(1 << 2)
 	uint32_t target;
 	uint32_t target_hart;
 };
@@ -146,15 +151,40 @@ aplic_set_enabled(struct aplic *aplic, bool write, uint64_t *val, bool enabled)
 	irq = &aplic->irqs[i];
 
 	mtx_lock_spin(&aplic->mtx);
-	if (enabled)
-		irq->state |= APLIC_IRQ_STATE_ENABLED;
-	else
-		irq->state &= ~APLIC_IRQ_STATE_ENABLED;
+	if ((irq->sourcecfg & SOURCECFG_SM_M) != SOURCECFG_SM_INACTIVE) {
+		if (enabled)
+			irq->state |= APLIC_IRQ_STATE_ENABLED;
+		else
+			irq->state &= ~APLIC_IRQ_STATE_ENABLED;
+	}
 	mtx_unlock_spin(&aplic->mtx);
 
 	return (0);
 }
 
+static void
+aplic_set_enabled_word(struct aplic *aplic, bool write, uint32_t word,
+    uint64_t *val, bool enabled)
+{
+	uint64_t v;
+	int i;
+
+	if (!write) {
+		*val = 0;
+		return;
+	}
+
+	/*
+	 * The write is ignored if value written is not an active interrupt
+	 * source number in the domain.
+	 */
+	for (i = 0; i < 32; i++)
+		if (*val & (1u << i)) {
+			v = word * 32 + i;
+			(void)aplic_set_enabled(aplic, write, &v, enabled);
+		}
+}
+
 static int
 aplic_handle_target(struct aplic *aplic, int i, bool write, uint64_t *val)
 {
@@ -238,6 +268,8 @@ aplic_mmio_access(struct hyp *hyp, struct aplic *aplic, uint64_t reg,
 	int r;
 	int i;
 
+	dprintf("%s: reg %lx\n", __func__, reg);
+
 	if ((reg >= APLIC_SOURCECFG(1)) &&
 	    (reg <= APLIC_SOURCECFG(aplic->nirqs))) {
 		i = ((reg - APLIC_SOURCECFG(1)) >> 2) + 1;
@@ -258,9 +290,20 @@ aplic_mmio_access(struct hyp *hyp, struct aplic *aplic, uint64_t reg,
 		return (error);
 	}
 
+	if ((reg >= APLIC_CLRIE) && (reg < (APLIC_CLRIE + aplic->nirqs * 4))) {
+		i = (reg - APLIC_CLRIE) >> 2;
+		aplic_set_enabled_word(aplic, write, i, val, false);
+		return (0);
+	}
+
 	switch (reg) {
 	case APLIC_DOMAINCFG:
-		aplic->domaincfg = *val & DOMAINCFG_IE;
+		mtx_lock_spin(&aplic->mtx);
+		if (write)
+			aplic->domaincfg = *val & DOMAINCFG_IE;
+		else
+			*val = aplic->domaincfg;
+		mtx_unlock_spin(&aplic->mtx);
 		error = 0;
 		break;
 	case APLIC_SETIENUM:
@@ -441,6 +484,7 @@ aplic_inject_irq(struct hyp *hyp, int vcpuid, uint32_t irqid, bool level)
 	struct aplic *aplic;
 	bool notify;
 	int error;
+	int mask;
 
 	aplic = hyp->aplic;
 
@@ -460,22 +504,39 @@ aplic_inject_irq(struct hyp *hyp, int vcpuid, uint32_t irqid, bool level)
 
 	notify = false;
 	switch (irq->sourcecfg & SOURCECFG_SM_M) {
+	case SOURCECFG_SM_LEVEL0:
+		if (!level)
+			irq->state |= APLIC_IRQ_STATE_PENDING;
+		break;
+	case SOURCECFG_SM_LEVEL1:
+		if (level)
+			irq->state |= APLIC_IRQ_STATE_PENDING;
+		break;
+	case SOURCECFG_SM_EDGE0:
+		if (!level && (irq->state & APLIC_IRQ_STATE_INPUT))
+			irq->state |= APLIC_IRQ_STATE_PENDING;
+		break;
 	case SOURCECFG_SM_EDGE1:
-		if (level) {
+		if (level && !(irq->state & APLIC_IRQ_STATE_INPUT))
 			irq->state |= APLIC_IRQ_STATE_PENDING;
-			if (irq->state & APLIC_IRQ_STATE_ENABLED)
-				notify = true;
-		} else
-			irq->state &= ~APLIC_IRQ_STATE_PENDING;
 		break;
 	case SOURCECFG_SM_DETACHED:
+	case SOURCECFG_SM_INACTIVE:
 		break;
 	default:
-		/* TODO. */
-		dprintf("sourcecfg %d\n", irq->sourcecfg & SOURCECFG_SM_M);
 		error = ENXIO;
 		break;
 	}
+
+	if (level)
+		irq->state |= APLIC_IRQ_STATE_INPUT;
+	else
+		irq->state &= ~APLIC_IRQ_STATE_INPUT;
+
+	mask = APLIC_IRQ_STATE_ENABLED | APLIC_IRQ_STATE_PENDING;
+	if ((irq->state & mask) == mask)
+		notify = true;
+
 	mtx_unlock_spin(&aplic->mtx);
 
 	if (notify)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502050934.5159YfUu025609>