All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices
@ 2026-04-28 16:00 Jim Shu
  2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Jim Shu @ 2026-04-28 16:00 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Jim Shu

Bugfix:
  - APLIC should also clear pending bit from rectified value when it is
    in the both level-trigger mode and direct delivery mode.

Enhancements:
  - Add reset API to APLIC and IMSIC device
  - Add trace events of APLIC read/write function

Jim Shu (4):
  hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode
  hw/intc: riscv_aplic: Add reset API to APLIC
  hw/intc: riscv_imsic: Add reset API to IMSIC
  hw/intc: riscv_aplic: add trace events of APLIC read/write function

 hw/intc/riscv_aplic.c | 116 +++++++++++++++++++++++++++++-------------
 hw/intc/riscv_imsic.c |  19 +++++++
 hw/intc/trace-events  |   4 ++
 3 files changed, 105 insertions(+), 34 deletions(-)

-- 
2.43.0



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode
  2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
@ 2026-04-28 16:01 ` Jim Shu
  2026-05-18 12:20   ` Daniel Henrique Barboza
  2026-05-18 21:56   ` Chao Liu
  2026-04-28 16:01 ` [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC Jim Shu
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 11+ messages in thread
From: Jim Shu @ 2026-04-28 16:01 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Jim Shu

According to the AIA spec ch4.7 ("Precise effects on interrupt-pending
bits"), pending bit of APLIC should be set/cleared whenever the
rectified input value is high/low in the both level-trigger mode
and direct delivery mode.

Currently, QEMU APLIC only clears the pending bit when interrupt is
claimed in APLIC, but not clears it when the rectified input value is
low. (e.g. IRQ source signal is low in the LEVEL_HIGH/Level1 mode).
The software may receive an additional IRQ if the peripheral
triggers one after the software clears the APLIC IRQ but before it
clears the peripheral's IRQ.

Thus, we also clear the pending bit via the rectified input value in the
level-trigger mode.

This change doesn't affect MSI delivery mode. Calling
riscv_aplic_msi_irq_update() when IRQ pending is low will do nothing.

Signed-off-by: Jim Shu <jim.shu@sifive.com>
---
 hw/intc/riscv_aplic.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index 8f700431114..791e0b01b96 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -591,14 +591,14 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
         }
         break;
     case APLIC_SOURCECFG_SM_LEVEL_HIGH:
-        if ((level > 0) && !(state & APLIC_ISTATE_PENDING)) {
-            riscv_aplic_set_pending_raw(aplic, irq, true);
+        if ((level > 0) != !!(state & APLIC_ISTATE_PENDING)) {
+            riscv_aplic_set_pending_raw(aplic, irq, level > 0);
             update = true;
         }
         break;
     case APLIC_SOURCECFG_SM_LEVEL_LOW:
-        if ((level <= 0) && !(state & APLIC_ISTATE_PENDING)) {
-            riscv_aplic_set_pending_raw(aplic, irq, true);
+        if ((level <= 0) != !!(state & APLIC_ISTATE_PENDING)) {
+            riscv_aplic_set_pending_raw(aplic, irq, level <= 0);
             update = true;
         }
         break;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC
  2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
  2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
@ 2026-04-28 16:01 ` Jim Shu
  2026-05-18 12:20   ` Daniel Henrique Barboza
  2026-04-28 16:01 ` [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC Jim Shu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Jim Shu @ 2026-04-28 16:01 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Jim Shu,
	Fea . Wang

Clearing APLIC registers and qemu_irq in the reset function

Signed-off-by: Jim Shu <jim.shu@sifive.com>
Signed-off-by: Fea.Wang <fea.wang@sifive.com>
---
 hw/intc/riscv_aplic.c | 45 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 40 insertions(+), 5 deletions(-)

diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index 791e0b01b96..a04e0e1a898 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -892,6 +892,44 @@ static const MemoryRegionOps riscv_aplic_ops = {
     }
 };
 
+static void riscv_aplic_reset_enter(Object *obj, ResetType type)
+{
+    RISCVAPLICState *aplic = RISCV_APLIC(obj);
+    int i;
+
+    aplic->domaincfg = 0;
+    memset(aplic->sourcecfg, 0, sizeof(uint32_t) * aplic->num_irqs);
+    memset(aplic->target, 0, sizeof(uint32_t) * aplic->num_irqs);
+    if (!aplic->msimode) {
+        for (i = 0; i < aplic->num_irqs; i++) {
+            aplic->target[i] = 1;
+        }
+    }
+
+    for (i = 0; i < aplic->num_irqs ; i++) {
+        riscv_aplic_set_enabled_raw(aplic, i, false);
+    }
+
+    /* Need to unlock [ms]msicfgaddrh.L */
+    aplic->mmsicfgaddr = 0;
+    aplic->mmsicfgaddrH = 0;
+    aplic->smsicfgaddr = 0;
+    aplic->smsicfgaddrH = 0;
+
+    if (!aplic->msimode) {
+        /* Reset IDC registers only in non-MSI mode */
+        for (i = 0; i < aplic->num_harts; i++) {
+            aplic->idelivery[i] = 0;
+            aplic->iforce[i] = 0;
+            aplic->ithreshold[i] = 0;
+        }
+
+        for (i = 0; i < aplic->num_harts; i++) {
+            qemu_irq_lower(aplic->external_irqs[i]);
+        }
+    }
+}
+
 static void riscv_aplic_realize(DeviceState *dev, Error **errp)
 {
     uint32_t i;
@@ -925,11 +963,6 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
         aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
         aplic->state = g_new0(uint32_t, aplic->num_irqs);
         aplic->target = g_new0(uint32_t, aplic->num_irqs);
-        if (!aplic->msimode) {
-            for (i = 0; i < aplic->num_irqs; i++) {
-                aplic->target[i] = 1;
-            }
-        }
         aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
         aplic->iforce = g_new0(uint32_t, aplic->num_harts);
         aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
@@ -1014,9 +1047,11 @@ static const VMStateDescription vmstate_riscv_aplic = {
 static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     device_class_set_props(dc, riscv_aplic_properties);
     dc->realize = riscv_aplic_realize;
+    rc->phases.enter = riscv_aplic_reset_enter;
     dc->vmsd = &vmstate_riscv_aplic;
 }
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC
  2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
  2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
  2026-04-28 16:01 ` [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC Jim Shu
@ 2026-04-28 16:01 ` Jim Shu
  2026-05-18 12:20   ` Daniel Henrique Barboza
  2026-04-28 16:01 ` [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function Jim Shu
  2026-05-19  4:46 ` [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Alistair Francis
  4 siblings, 1 reply; 11+ messages in thread
From: Jim Shu @ 2026-04-28 16:01 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Jim Shu

Clearing IMSIC registers and qemu_irq in the reset function

Signed-off-by: Jim Shu <jim.shu@sifive.com>
---
 hw/intc/riscv_imsic.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index 7c9a0120335..ac59496c22b 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -342,6 +342,23 @@ static const MemoryRegionOps riscv_imsic_ops = {
     }
 };
 
+static void riscv_imsic_reset_enter(Object *obj, ResetType type)
+{
+    RISCVIMSICState *imsic = RISCV_IMSIC(obj);
+    int i;
+
+    memset(imsic->eidelivery, 0, sizeof(uint32_t) * imsic->num_pages);
+    memset(imsic->eithreshold, 0, sizeof(uint32_t) * imsic->num_pages);
+
+    for (i = 0; i < imsic->num_eistate; i++) {
+        imsic->eistate[i] &= ~IMSIC_EISTATE_ENABLED;
+    }
+
+    for (i = 0; i < imsic->num_pages; i++) {
+        qemu_irq_lower(imsic->external_irqs[i]);
+    }
+}
+
 static void riscv_imsic_realize(DeviceState *dev, Error **errp)
 {
     RISCVIMSICState *imsic = RISCV_IMSIC(dev);
@@ -425,9 +442,11 @@ static const VMStateDescription vmstate_riscv_imsic = {
 static void riscv_imsic_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     device_class_set_props(dc, riscv_imsic_properties);
     dc->realize = riscv_imsic_realize;
+    rc->phases.enter = riscv_imsic_reset_enter;
     dc->vmsd = &vmstate_riscv_imsic;
 }
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function
  2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
                   ` (2 preceding siblings ...)
  2026-04-28 16:01 ` [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC Jim Shu
@ 2026-04-28 16:01 ` Jim Shu
  2026-05-18 12:20   ` Daniel Henrique Barboza
  2026-05-19  4:46 ` [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Alistair Francis
  4 siblings, 1 reply; 11+ messages in thread
From: Jim Shu @ 2026-04-28 16:01 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, Jim Shu

Add the trace events for APLIC read/write functions.

Signed-off-by: Jim Shu <jim.shu@sifive.com>
---
 hw/intc/riscv_aplic.c | 63 ++++++++++++++++++++++++++-----------------
 hw/intc/trace-events  |  4 +++
 2 files changed, 42 insertions(+), 25 deletions(-)

diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index a04e0e1a898..55515d1a085 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -35,6 +35,7 @@
 #include "system/tcg.h"
 #include "kvm/kvm_riscv.h"
 #include "migration/vmstate.h"
+#include "trace.h"
 
 #define APLIC_MAX_IDC                  (1UL << 14)
 #define APLIC_MAX_SOURCE               1024
@@ -626,6 +627,7 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
 static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
 {
     uint32_t irq, word, idc;
+    uint64_t val;
     RISCVAPLICState *aplic = opaque;
 
     /* Reads must be 4 byte words */
@@ -634,18 +636,18 @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
     }
 
     if (addr == APLIC_DOMAINCFG) {
-        return APLIC_DOMAINCFG_RDONLY | aplic->domaincfg |
-               (aplic->msimode ? APLIC_DOMAINCFG_DM : 0);
+        val = APLIC_DOMAINCFG_RDONLY | aplic->domaincfg |
+              (aplic->msimode ? APLIC_DOMAINCFG_DM : 0);
     } else if ((APLIC_SOURCECFG_BASE <= addr) &&
             (addr < (APLIC_SOURCECFG_BASE + (aplic->num_irqs - 1) * 4))) {
         irq  = ((addr - APLIC_SOURCECFG_BASE) >> 2) + 1;
-        return aplic->sourcecfg[irq];
+        val = aplic->sourcecfg[irq];
     } else if (aplic->mmode && aplic->msimode &&
                (addr == APLIC_MMSICFGADDR)) {
-        return aplic->mmsicfgaddr;
+        val = aplic->mmsicfgaddr;
     } else if (aplic->mmode && aplic->msimode &&
                (addr == APLIC_MMSICFGADDRH)) {
-        return aplic->mmsicfgaddrH;
+        val = aplic->mmsicfgaddrH;
     } else if (aplic->mmode && aplic->msimode &&
                (addr == APLIC_SMSICFGADDR)) {
         /*
@@ -657,65 +659,74 @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
          *     only zero in at least one of the supervisor-level child
          * domains).
          */
-        return (aplic->num_children) ? aplic->smsicfgaddr : 0;
+        val = (aplic->num_children) ? aplic->smsicfgaddr : 0;
     } else if (aplic->mmode && aplic->msimode &&
                (addr == APLIC_SMSICFGADDRH)) {
-        return (aplic->num_children) ? aplic->smsicfgaddrH : 0;
+        val = (aplic->num_children) ? aplic->smsicfgaddrH : 0;
     } else if ((APLIC_SETIP_BASE <= addr) &&
             (addr < (APLIC_SETIP_BASE + aplic->bitfield_words * 4))) {
         word = (addr - APLIC_SETIP_BASE) >> 2;
-        return riscv_aplic_read_pending_word(aplic, word);
+        val = riscv_aplic_read_pending_word(aplic, word);
     } else if (addr == APLIC_SETIPNUM) {
-        return 0;
+        val = 0;
     } else if ((APLIC_CLRIP_BASE <= addr) &&
             (addr < (APLIC_CLRIP_BASE + aplic->bitfield_words * 4))) {
         word = (addr - APLIC_CLRIP_BASE) >> 2;
-        return riscv_aplic_read_input_word(aplic, word);
+        val = riscv_aplic_read_input_word(aplic, word);
     } else if (addr == APLIC_CLRIPNUM) {
-        return 0;
+        val = 0;
     } else if ((APLIC_SETIE_BASE <= addr) &&
             (addr < (APLIC_SETIE_BASE + aplic->bitfield_words * 4))) {
         word = (addr - APLIC_SETIE_BASE) >> 2;
-        return riscv_aplic_read_enabled_word(aplic, word);
+        val = riscv_aplic_read_enabled_word(aplic, word);
     } else if (addr == APLIC_SETIENUM) {
-        return 0;
+        val = 0;
     } else if ((APLIC_CLRIE_BASE <= addr) &&
             (addr < (APLIC_CLRIE_BASE + aplic->bitfield_words * 4))) {
-        return 0;
+        val = 0;
     } else if (addr == APLIC_CLRIENUM) {
-        return 0;
+        val = 0;
     } else if (addr == APLIC_SETIPNUM_LE) {
-        return 0;
+        val = 0;
     } else if (addr == APLIC_SETIPNUM_BE) {
-        return 0;
+        val = 0;
     } else if (addr == APLIC_GENMSI) {
-        return (aplic->msimode) ? aplic->genmsi : 0;
+        val = (aplic->msimode) ? aplic->genmsi : 0;
     } else if ((APLIC_TARGET_BASE <= addr) &&
             (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) {
         irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1;
         if (!riscv_aplic_source_active(aplic, irq)) {
-            return 0;
+            val = 0;
+        } else {
+            val = aplic->target[irq];
         }
-        return aplic->target[irq];
     } else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) &&
             (addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) {
         idc = (addr - APLIC_IDC_BASE) / APLIC_IDC_SIZE;
         switch (addr - (APLIC_IDC_BASE + idc * APLIC_IDC_SIZE)) {
         case APLIC_IDC_IDELIVERY:
-            return aplic->idelivery[idc];
+            val = aplic->idelivery[idc];
+            break;
         case APLIC_IDC_IFORCE:
-            return aplic->iforce[idc];
+            val = aplic->iforce[idc];
+            break;
         case APLIC_IDC_ITHRESHOLD:
-            return aplic->ithreshold[idc];
+            val = aplic->ithreshold[idc];
+            break;
         case APLIC_IDC_TOPI:
-            return riscv_aplic_idc_topi(aplic, idc);
+            val = riscv_aplic_idc_topi(aplic, idc);
+            break;
         case APLIC_IDC_CLAIMI:
-            return riscv_aplic_idc_claimi(aplic, idc);
+            val = riscv_aplic_idc_claimi(aplic, idc);
+            break;
         default:
             goto err;
         };
     }
 
+    trace_riscv_aplic_read(addr, size, val);
+    return val;
+
 err:
     qemu_log_mask(LOG_GUEST_ERROR,
                   "%s: Invalid register read 0x%" HWADDR_PRIx "\n",
@@ -734,6 +745,8 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
         goto err;
     }
 
+    trace_riscv_aplic_write(addr, size, value);
+
     if (addr == APLIC_DOMAINCFG) {
         /* Only IE bit writable at the moment */
         value &= APLIC_DOMAINCFG_IE;
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 018c609ca5e..36ea75049ab 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -330,3 +330,7 @@ loongarch_msi_set_irq(int irq_num) "set msi irq %d"
 loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d"
 loongarch_extioi_readw(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64
 loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64
+
+# riscv_aplic.c
+riscv_aplic_read(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64
+riscv_aplic_write(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode
  2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
@ 2026-05-18 12:20   ` Daniel Henrique Barboza
  2026-05-18 21:56   ` Chao Liu
  1 sibling, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2026-05-18 12:20 UTC (permalink / raw)
  To: Jim Shu, qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei, Chao Liu



On 4/28/2026 1:01 PM, Jim Shu wrote:
> According to the AIA spec ch4.7 ("Precise effects on interrupt-pending
> bits"), pending bit of APLIC should be set/cleared whenever the
> rectified input value is high/low in the both level-trigger mode
> and direct delivery mode.
> 
> Currently, QEMU APLIC only clears the pending bit when interrupt is
> claimed in APLIC, but not clears it when the rectified input value is
> low. (e.g. IRQ source signal is low in the LEVEL_HIGH/Level1 mode).
> The software may receive an additional IRQ if the peripheral
> triggers one after the software clears the APLIC IRQ but before it
> clears the peripheral's IRQ.
> 
> Thus, we also clear the pending bit via the rectified input value in the
> level-trigger mode.
> 
> This change doesn't affect MSI delivery mode. Calling
> riscv_aplic_msi_irq_update() when IRQ pending is low will do nothing.
> 
> Signed-off-by: Jim Shu <jim.shu@sifive.com>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   hw/intc/riscv_aplic.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
> index 8f700431114..791e0b01b96 100644
> --- a/hw/intc/riscv_aplic.c
> +++ b/hw/intc/riscv_aplic.c
> @@ -591,14 +591,14 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
>           }
>           break;
>       case APLIC_SOURCECFG_SM_LEVEL_HIGH:
> -        if ((level > 0) && !(state & APLIC_ISTATE_PENDING)) {
> -            riscv_aplic_set_pending_raw(aplic, irq, true);
> +        if ((level > 0) != !!(state & APLIC_ISTATE_PENDING)) {
> +            riscv_aplic_set_pending_raw(aplic, irq, level > 0);
>               update = true;
>           }
>           break;
>       case APLIC_SOURCECFG_SM_LEVEL_LOW:
> -        if ((level <= 0) && !(state & APLIC_ISTATE_PENDING)) {
> -            riscv_aplic_set_pending_raw(aplic, irq, true);
> +        if ((level <= 0) != !!(state & APLIC_ISTATE_PENDING)) {
> +            riscv_aplic_set_pending_raw(aplic, irq, level <= 0);
>               update = true;
>           }
>           break;



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC
  2026-04-28 16:01 ` [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC Jim Shu
@ 2026-05-18 12:20   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2026-05-18 12:20 UTC (permalink / raw)
  To: Jim Shu, qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei, Chao Liu,
	Fea . Wang



On 4/28/2026 1:01 PM, Jim Shu wrote:
> Clearing APLIC registers and qemu_irq in the reset function
> 
> Signed-off-by: Jim Shu <jim.shu@sifive.com>
> Signed-off-by: Fea.Wang <fea.wang@sifive.com>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   hw/intc/riscv_aplic.c | 45 ++++++++++++++++++++++++++++++++++++++-----
>   1 file changed, 40 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
> index 791e0b01b96..a04e0e1a898 100644
> --- a/hw/intc/riscv_aplic.c
> +++ b/hw/intc/riscv_aplic.c
> @@ -892,6 +892,44 @@ static const MemoryRegionOps riscv_aplic_ops = {
>       }
>   };
>   
> +static void riscv_aplic_reset_enter(Object *obj, ResetType type)
> +{
> +    RISCVAPLICState *aplic = RISCV_APLIC(obj);
> +    int i;
> +
> +    aplic->domaincfg = 0;
> +    memset(aplic->sourcecfg, 0, sizeof(uint32_t) * aplic->num_irqs);
> +    memset(aplic->target, 0, sizeof(uint32_t) * aplic->num_irqs);
> +    if (!aplic->msimode) {
> +        for (i = 0; i < aplic->num_irqs; i++) {
> +            aplic->target[i] = 1;
> +        }
> +    }
> +
> +    for (i = 0; i < aplic->num_irqs ; i++) {
> +        riscv_aplic_set_enabled_raw(aplic, i, false);
> +    }
> +
> +    /* Need to unlock [ms]msicfgaddrh.L */
> +    aplic->mmsicfgaddr = 0;
> +    aplic->mmsicfgaddrH = 0;
> +    aplic->smsicfgaddr = 0;
> +    aplic->smsicfgaddrH = 0;
> +
> +    if (!aplic->msimode) {
> +        /* Reset IDC registers only in non-MSI mode */
> +        for (i = 0; i < aplic->num_harts; i++) {
> +            aplic->idelivery[i] = 0;
> +            aplic->iforce[i] = 0;
> +            aplic->ithreshold[i] = 0;
> +        }
> +
> +        for (i = 0; i < aplic->num_harts; i++) {
> +            qemu_irq_lower(aplic->external_irqs[i]);
> +        }
> +    }
> +}
> +
>   static void riscv_aplic_realize(DeviceState *dev, Error **errp)
>   {
>       uint32_t i;
> @@ -925,11 +963,6 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
>           aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
>           aplic->state = g_new0(uint32_t, aplic->num_irqs);
>           aplic->target = g_new0(uint32_t, aplic->num_irqs);
> -        if (!aplic->msimode) {
> -            for (i = 0; i < aplic->num_irqs; i++) {
> -                aplic->target[i] = 1;
> -            }
> -        }
>           aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
>           aplic->iforce = g_new0(uint32_t, aplic->num_harts);
>           aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
> @@ -1014,9 +1047,11 @@ static const VMStateDescription vmstate_riscv_aplic = {
>   static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
>   {
>       DeviceClass *dc = DEVICE_CLASS(klass);
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);
>   
>       device_class_set_props(dc, riscv_aplic_properties);
>       dc->realize = riscv_aplic_realize;
> +    rc->phases.enter = riscv_aplic_reset_enter;
>       dc->vmsd = &vmstate_riscv_aplic;
>   }
>   



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC
  2026-04-28 16:01 ` [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC Jim Shu
@ 2026-05-18 12:20   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2026-05-18 12:20 UTC (permalink / raw)
  To: Jim Shu, qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei, Chao Liu



On 4/28/2026 1:01 PM, Jim Shu wrote:
> Clearing IMSIC registers and qemu_irq in the reset function
> 
> Signed-off-by: Jim Shu <jim.shu@sifive.com>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   hw/intc/riscv_imsic.c | 19 +++++++++++++++++++
>   1 file changed, 19 insertions(+)
> 
> diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
> index 7c9a0120335..ac59496c22b 100644
> --- a/hw/intc/riscv_imsic.c
> +++ b/hw/intc/riscv_imsic.c
> @@ -342,6 +342,23 @@ static const MemoryRegionOps riscv_imsic_ops = {
>       }
>   };
>   
> +static void riscv_imsic_reset_enter(Object *obj, ResetType type)
> +{
> +    RISCVIMSICState *imsic = RISCV_IMSIC(obj);
> +    int i;
> +
> +    memset(imsic->eidelivery, 0, sizeof(uint32_t) * imsic->num_pages);
> +    memset(imsic->eithreshold, 0, sizeof(uint32_t) * imsic->num_pages);
> +
> +    for (i = 0; i < imsic->num_eistate; i++) {
> +        imsic->eistate[i] &= ~IMSIC_EISTATE_ENABLED;
> +    }
> +
> +    for (i = 0; i < imsic->num_pages; i++) {
> +        qemu_irq_lower(imsic->external_irqs[i]);
> +    }
> +}
> +
>   static void riscv_imsic_realize(DeviceState *dev, Error **errp)
>   {
>       RISCVIMSICState *imsic = RISCV_IMSIC(dev);
> @@ -425,9 +442,11 @@ static const VMStateDescription vmstate_riscv_imsic = {
>   static void riscv_imsic_class_init(ObjectClass *klass, const void *data)
>   {
>       DeviceClass *dc = DEVICE_CLASS(klass);
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);
>   
>       device_class_set_props(dc, riscv_imsic_properties);
>       dc->realize = riscv_imsic_realize;
> +    rc->phases.enter = riscv_imsic_reset_enter;
>       dc->vmsd = &vmstate_riscv_imsic;
>   }
>   



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function
  2026-04-28 16:01 ` [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function Jim Shu
@ 2026-05-18 12:20   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2026-05-18 12:20 UTC (permalink / raw)
  To: Jim Shu, qemu-devel, qemu-riscv
  Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei, Chao Liu



On 4/28/2026 1:01 PM, Jim Shu wrote:
> Add the trace events for APLIC read/write functions.
> 
> Signed-off-by: Jim Shu <jim.shu@sifive.com>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   hw/intc/riscv_aplic.c | 63 ++++++++++++++++++++++++++-----------------
>   hw/intc/trace-events  |  4 +++
>   2 files changed, 42 insertions(+), 25 deletions(-)
> 
> diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
> index a04e0e1a898..55515d1a085 100644
> --- a/hw/intc/riscv_aplic.c
> +++ b/hw/intc/riscv_aplic.c
> @@ -35,6 +35,7 @@
>   #include "system/tcg.h"
>   #include "kvm/kvm_riscv.h"
>   #include "migration/vmstate.h"
> +#include "trace.h"
>   
>   #define APLIC_MAX_IDC                  (1UL << 14)
>   #define APLIC_MAX_SOURCE               1024
> @@ -626,6 +627,7 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
>   static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
>   {
>       uint32_t irq, word, idc;
> +    uint64_t val;
>       RISCVAPLICState *aplic = opaque;
>   
>       /* Reads must be 4 byte words */
> @@ -634,18 +636,18 @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
>       }
>   
>       if (addr == APLIC_DOMAINCFG) {
> -        return APLIC_DOMAINCFG_RDONLY | aplic->domaincfg |
> -               (aplic->msimode ? APLIC_DOMAINCFG_DM : 0);
> +        val = APLIC_DOMAINCFG_RDONLY | aplic->domaincfg |
> +              (aplic->msimode ? APLIC_DOMAINCFG_DM : 0);
>       } else if ((APLIC_SOURCECFG_BASE <= addr) &&
>               (addr < (APLIC_SOURCECFG_BASE + (aplic->num_irqs - 1) * 4))) {
>           irq  = ((addr - APLIC_SOURCECFG_BASE) >> 2) + 1;
> -        return aplic->sourcecfg[irq];
> +        val = aplic->sourcecfg[irq];
>       } else if (aplic->mmode && aplic->msimode &&
>                  (addr == APLIC_MMSICFGADDR)) {
> -        return aplic->mmsicfgaddr;
> +        val = aplic->mmsicfgaddr;
>       } else if (aplic->mmode && aplic->msimode &&
>                  (addr == APLIC_MMSICFGADDRH)) {
> -        return aplic->mmsicfgaddrH;
> +        val = aplic->mmsicfgaddrH;
>       } else if (aplic->mmode && aplic->msimode &&
>                  (addr == APLIC_SMSICFGADDR)) {
>           /*
> @@ -657,65 +659,74 @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
>            *     only zero in at least one of the supervisor-level child
>            * domains).
>            */
> -        return (aplic->num_children) ? aplic->smsicfgaddr : 0;
> +        val = (aplic->num_children) ? aplic->smsicfgaddr : 0;
>       } else if (aplic->mmode && aplic->msimode &&
>                  (addr == APLIC_SMSICFGADDRH)) {
> -        return (aplic->num_children) ? aplic->smsicfgaddrH : 0;
> +        val = (aplic->num_children) ? aplic->smsicfgaddrH : 0;
>       } else if ((APLIC_SETIP_BASE <= addr) &&
>               (addr < (APLIC_SETIP_BASE + aplic->bitfield_words * 4))) {
>           word = (addr - APLIC_SETIP_BASE) >> 2;
> -        return riscv_aplic_read_pending_word(aplic, word);
> +        val = riscv_aplic_read_pending_word(aplic, word);
>       } else if (addr == APLIC_SETIPNUM) {
> -        return 0;
> +        val = 0;
>       } else if ((APLIC_CLRIP_BASE <= addr) &&
>               (addr < (APLIC_CLRIP_BASE + aplic->bitfield_words * 4))) {
>           word = (addr - APLIC_CLRIP_BASE) >> 2;
> -        return riscv_aplic_read_input_word(aplic, word);
> +        val = riscv_aplic_read_input_word(aplic, word);
>       } else if (addr == APLIC_CLRIPNUM) {
> -        return 0;
> +        val = 0;
>       } else if ((APLIC_SETIE_BASE <= addr) &&
>               (addr < (APLIC_SETIE_BASE + aplic->bitfield_words * 4))) {
>           word = (addr - APLIC_SETIE_BASE) >> 2;
> -        return riscv_aplic_read_enabled_word(aplic, word);
> +        val = riscv_aplic_read_enabled_word(aplic, word);
>       } else if (addr == APLIC_SETIENUM) {
> -        return 0;
> +        val = 0;
>       } else if ((APLIC_CLRIE_BASE <= addr) &&
>               (addr < (APLIC_CLRIE_BASE + aplic->bitfield_words * 4))) {
> -        return 0;
> +        val = 0;
>       } else if (addr == APLIC_CLRIENUM) {
> -        return 0;
> +        val = 0;
>       } else if (addr == APLIC_SETIPNUM_LE) {
> -        return 0;
> +        val = 0;
>       } else if (addr == APLIC_SETIPNUM_BE) {
> -        return 0;
> +        val = 0;
>       } else if (addr == APLIC_GENMSI) {
> -        return (aplic->msimode) ? aplic->genmsi : 0;
> +        val = (aplic->msimode) ? aplic->genmsi : 0;
>       } else if ((APLIC_TARGET_BASE <= addr) &&
>               (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) {
>           irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1;
>           if (!riscv_aplic_source_active(aplic, irq)) {
> -            return 0;
> +            val = 0;
> +        } else {
> +            val = aplic->target[irq];
>           }
> -        return aplic->target[irq];
>       } else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) &&
>               (addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) {
>           idc = (addr - APLIC_IDC_BASE) / APLIC_IDC_SIZE;
>           switch (addr - (APLIC_IDC_BASE + idc * APLIC_IDC_SIZE)) {
>           case APLIC_IDC_IDELIVERY:
> -            return aplic->idelivery[idc];
> +            val = aplic->idelivery[idc];
> +            break;
>           case APLIC_IDC_IFORCE:
> -            return aplic->iforce[idc];
> +            val = aplic->iforce[idc];
> +            break;
>           case APLIC_IDC_ITHRESHOLD:
> -            return aplic->ithreshold[idc];
> +            val = aplic->ithreshold[idc];
> +            break;
>           case APLIC_IDC_TOPI:
> -            return riscv_aplic_idc_topi(aplic, idc);
> +            val = riscv_aplic_idc_topi(aplic, idc);
> +            break;
>           case APLIC_IDC_CLAIMI:
> -            return riscv_aplic_idc_claimi(aplic, idc);
> +            val = riscv_aplic_idc_claimi(aplic, idc);
> +            break;
>           default:
>               goto err;
>           };
>       }
>   
> +    trace_riscv_aplic_read(addr, size, val);
> +    return val;
> +
>   err:
>       qemu_log_mask(LOG_GUEST_ERROR,
>                     "%s: Invalid register read 0x%" HWADDR_PRIx "\n",
> @@ -734,6 +745,8 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
>           goto err;
>       }
>   
> +    trace_riscv_aplic_write(addr, size, value);
> +
>       if (addr == APLIC_DOMAINCFG) {
>           /* Only IE bit writable at the moment */
>           value &= APLIC_DOMAINCFG_IE;
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 018c609ca5e..36ea75049ab 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -330,3 +330,7 @@ loongarch_msi_set_irq(int irq_num) "set msi irq %d"
>   loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d"
>   loongarch_extioi_readw(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64
>   loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64
> +
> +# riscv_aplic.c
> +riscv_aplic_read(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64
> +riscv_aplic_write(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode
  2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
  2026-05-18 12:20   ` Daniel Henrique Barboza
@ 2026-05-18 21:56   ` Chao Liu
  1 sibling, 0 replies; 11+ messages in thread
From: Chao Liu @ 2026-05-18 21:56 UTC (permalink / raw)
  To: Jim Shu
  Cc: qemu-devel, qemu-riscv, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei

On Wed, Apr 29, 2026 at 12:01:00AM +0800, Jim Shu wrote:
> According to the AIA spec ch4.7 ("Precise effects on interrupt-pending
> bits"), pending bit of APLIC should be set/cleared whenever the
> rectified input value is high/low in the both level-trigger mode
> and direct delivery mode.
> 
> Currently, QEMU APLIC only clears the pending bit when interrupt is
> claimed in APLIC, but not clears it when the rectified input value is
> low. (e.g. IRQ source signal is low in the LEVEL_HIGH/Level1 mode).
> The software may receive an additional IRQ if the peripheral
> triggers one after the software clears the APLIC IRQ but before it
> clears the peripheral's IRQ.
> 
> Thus, we also clear the pending bit via the rectified input value in the
> level-trigger mode.
> 
> This change doesn't affect MSI delivery mode. Calling
> riscv_aplic_msi_irq_update() when IRQ pending is low will do nothing.
> 
> Signed-off-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>

Thanks,
Chao
> ---
>  hw/intc/riscv_aplic.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
> index 8f700431114..791e0b01b96 100644
> --- a/hw/intc/riscv_aplic.c
> +++ b/hw/intc/riscv_aplic.c
> @@ -591,14 +591,14 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
>          }
>          break;
>      case APLIC_SOURCECFG_SM_LEVEL_HIGH:
> -        if ((level > 0) && !(state & APLIC_ISTATE_PENDING)) {
> -            riscv_aplic_set_pending_raw(aplic, irq, true);
> +        if ((level > 0) != !!(state & APLIC_ISTATE_PENDING)) {
> +            riscv_aplic_set_pending_raw(aplic, irq, level > 0);
>              update = true;
>          }
>          break;
>      case APLIC_SOURCECFG_SM_LEVEL_LOW:
> -        if ((level <= 0) && !(state & APLIC_ISTATE_PENDING)) {
> -            riscv_aplic_set_pending_raw(aplic, irq, true);
> +        if ((level <= 0) != !!(state & APLIC_ISTATE_PENDING)) {
> +            riscv_aplic_set_pending_raw(aplic, irq, level <= 0);
>              update = true;
>          }
>          break;
> -- 
> 2.43.0
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices
  2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
                   ` (3 preceding siblings ...)
  2026-04-28 16:01 ` [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function Jim Shu
@ 2026-05-19  4:46 ` Alistair Francis
  4 siblings, 0 replies; 11+ messages in thread
From: Alistair Francis @ 2026-05-19  4:46 UTC (permalink / raw)
  To: Jim Shu
  Cc: qemu-devel, qemu-riscv, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Chao Liu

On Wed, Apr 29, 2026 at 2:04 AM Jim Shu <jim.shu@sifive.com> wrote:
>
> Bugfix:
>   - APLIC should also clear pending bit from rectified value when it is
>     in the both level-trigger mode and direct delivery mode.
>
> Enhancements:
>   - Add reset API to APLIC and IMSIC device
>   - Add trace events of APLIC read/write function
>
> Jim Shu (4):
>   hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode
>   hw/intc: riscv_aplic: Add reset API to APLIC
>   hw/intc: riscv_imsic: Add reset API to IMSIC
>   hw/intc: riscv_aplic: add trace events of APLIC read/write function

Thanks!

Applied to riscv-to-apply.next

Alistair

>
>  hw/intc/riscv_aplic.c | 116 +++++++++++++++++++++++++++++-------------
>  hw/intc/riscv_imsic.c |  19 +++++++
>  hw/intc/trace-events  |   4 ++
>  3 files changed, 105 insertions(+), 34 deletions(-)
>
> --
> 2.43.0
>
>


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-05-19  4:47 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28 16:00 [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Jim Shu
2026-04-28 16:01 ` [PATCH 1/4] hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode Jim Shu
2026-05-18 12:20   ` Daniel Henrique Barboza
2026-05-18 21:56   ` Chao Liu
2026-04-28 16:01 ` [PATCH 2/4] hw/intc: riscv_aplic: Add reset API to APLIC Jim Shu
2026-05-18 12:20   ` Daniel Henrique Barboza
2026-04-28 16:01 ` [PATCH 3/4] hw/intc: riscv_imsic: Add reset API to IMSIC Jim Shu
2026-05-18 12:20   ` Daniel Henrique Barboza
2026-04-28 16:01 ` [PATCH 4/4] hw/intc: riscv_aplic: add trace events of APLIC read/write function Jim Shu
2026-05-18 12:20   ` Daniel Henrique Barboza
2026-05-19  4:46 ` [PATCH 0/4] Minor fixes and enhancements of RISC-V AIA devices Alistair Francis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.