summary refs log tree commit diff stats
path: root/hw/intc/riscv_imsic.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-10-02 16:30:06 +0100
committerPeter Maydell <peter.maydell@linaro.org>2024-10-02 16:30:06 +0100
commit35ba77d2fcd10efd6db8318bbd4d21fa9402143b (patch)
treeeca8fdc9bd67c063dcef30e47385d587e30b3070 /hw/intc/riscv_imsic.c
parenta3500b22a18ec4195793037c0f45a47bd5a59e51 (diff)
parent74b493244d0624afed22606e76fc7fca62777401 (diff)
downloadfocaccia-qemu-35ba77d2fcd10efd6db8318bbd4d21fa9402143b.tar.gz
focaccia-qemu-35ba77d2fcd10efd6db8318bbd4d21fa9402143b.zip
Merge tag 'pull-riscv-to-apply-20241002' of https://github.com/alistair23/qemu into staging
RISC-V PR for 9.2

* Add a property to set vl to ceil(AVL/2)
* Enable numamem testing for RISC-V
* Consider MISA bit choice in implied rule
* Fix the za64rs priv spec requirements
* Enable Bit Manip for OpenTitan Ibex CPU
* Fix the group bit setting of AIA with KVM
* Stop timer with infinite timecmp
* Add 'fcsr' register to QEMU log as a part of F extension
* Fix riscv64 build on musl libc
* Add preliminary textra trigger CSR functions
* RISC-V bsd-user support
* Respect firmware ELF entry point
* Add Svvptc extension support
* Fix masking of rv32 physical address
* Fix linking problem with semihosting disabled
* Fix IMSIC interrupt state updates

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmb83lYACgkQr3yVEwxT
# gBNndBAAmh66yWt9TeTHlQ/rgBhx2nUMBbfICBWQyNGvPlslffwrNoLkh8jpkuiP
# PD0RQArAAGeM09cgCZCu14JzIBmmNiGgUxsUnqOZvUw18uIlLFlpt/tiT7iGw/Xb
# pfI7waF66/FPXBErY2yiw9/RGQLlkiGNBC9FNYrD/kCahf9MSIobv85tOgSQ2qjH
# nOJ+UBN0TQ1x0Z5lJMj9Pzl1WDvelRnCkYI5nXg1heKG73Hm7GmHt99QpTV2Okqn
# T3jFzEfMTQeHO4nC/X2pbaesE62K+mTg/FZpId2iV8lMCSm1zKof+xJ4boKM9RB2
# 0HjXAT+MveLuLUNtgfbV9C+VgU25M+wnfy5tH0l801Y/Gez8Q1fbK2uykuiyiUSy
# MNNk/KzmOYuffwItuyeL3mmWHXsN+izUIeMmMxfL9X9nssZXRsrDXc+MByS7w0fk
# QOeZmXHTxXwxFymr0t0DLK2eKEG6cqQty1KWp6iLx3uwnMTGo+576P41Q+boj64s
# VllWzmuR0Ta0xuSR4sDvEFCO7OCFEgVdn1j0FvhRFskPEDrbQgXRLq8i3awtU6z1
# NIh+A30XeK+EZLv0sEje6gav5lZHWMfAeCOKJstVzOl8+NQibuKTUrsqLgTrBK6K
# plw8qwvZYjSnYErzHfywlq9ArufIvOHYcx9Nb76tLNy9E+y01yo=
# =15Hm
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 02 Oct 2024 06:47:02 BST
# gpg:                using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65  9296 AF7C 9513 0C53 8013

* tag 'pull-riscv-to-apply-20241002' of https://github.com/alistair23/qemu: (35 commits)
  bsd-user: Add RISC-V 64-bit Target Configuration and Debug XML Files
  bsd-user: Implement set_mcontext and get_ucontext_sigreturn for RISCV
  bsd-user: Implement 'get_mcontext' for RISC-V
  bsd-user: Implement RISC-V signal trampoline setup functions
  bsd-user: Define RISC-V signal handling structures and constants
  bsd-user: Add generic RISC-V64 target definitions
  bsd-user: Define RISC-V system call structures and constants
  bsd-user: Define RISC-V VM parameters and helper functions
  bsd-user: Add RISC-V thread setup and initialization support
  bsd-user: Implement RISC-V sysarch system call emulation
  bsd-user: Add RISC-V signal trampoline setup function
  bsd-user: Define RISC-V register structures and register copying
  bsd-user: Add RISC-V ELF definitions and hardware capability detection
  bsd-user: Implement RISC-V TLS register setup
  bsd-user: Implement RISC-V CPU register cloning and reset functions
  bsd-user: Add RISC-V CPU execution loop and syscall handling
  bsd-user: Implement RISC-V CPU initialization and main loop
  hw/intc: riscv-imsic: Fix interrupt state updates.
  target/riscv/cpu_helper: Fix linking problem with semihosting disabled
  target/riscv32: Fix masking of physical address
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc/riscv_imsic.c')
-rw-r--r--hw/intc/riscv_imsic.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index b90f0d731d..9ef65d4012 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -55,7 +55,7 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
                (imsic->eithreshold[page] <= imsic->num_irqs)) ?
                imsic->eithreshold[page] : imsic->num_irqs;
     for (i = 1; i < max_irq; i++) {
-        if ((imsic->eistate[base + i] & IMSIC_EISTATE_ENPEND) ==
+        if ((qatomic_read(&imsic->eistate[base + i]) & IMSIC_EISTATE_ENPEND) ==
                 IMSIC_EISTATE_ENPEND) {
             return (i << IMSIC_TOPEI_IID_SHIFT) | i;
         }
@@ -66,10 +66,24 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
 
 static void riscv_imsic_update(RISCVIMSICState *imsic, uint32_t page)
 {
+    uint32_t base = page * imsic->num_irqs;
+
+    /*
+     * Lower the interrupt line if necessary, then evaluate the current
+     * IMSIC state.
+     * This sequence ensures that any race between evaluating the eistate and
+     * updating the interrupt line will not result in an incorrectly
+     * deactivated connected CPU IRQ line.
+     * If multiple interrupts are pending, this sequence functions identically
+     * to qemu_irq_pulse.
+     */
+
+    if (qatomic_fetch_and(&imsic->eistate[base], ~IMSIC_EISTATE_ENPEND)) {
+        qemu_irq_lower(imsic->external_irqs[page]);
+    }
     if (imsic->eidelivery[page] && riscv_imsic_topei(imsic, page)) {
         qemu_irq_raise(imsic->external_irqs[page]);
-    } else {
-        qemu_irq_lower(imsic->external_irqs[page]);
+        qatomic_or(&imsic->eistate[base], IMSIC_EISTATE_ENPEND);
     }
 }
 
@@ -125,12 +139,11 @@ static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page,
         topei >>= IMSIC_TOPEI_IID_SHIFT;
         base = page * imsic->num_irqs;
         if (topei) {
-            imsic->eistate[base + topei] &= ~IMSIC_EISTATE_PENDING;
+            qatomic_and(&imsic->eistate[base + topei], ~IMSIC_EISTATE_PENDING);
         }
-
-        riscv_imsic_update(imsic, page);
     }
 
+    riscv_imsic_update(imsic, page);
     return 0;
 }
 
@@ -139,7 +152,7 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
                                uint32_t num, bool pend, target_ulong *val,
                                target_ulong new_val, target_ulong wr_mask)
 {
-    uint32_t i, base;
+    uint32_t i, base, prev;
     target_ulong mask;
     uint32_t state = (pend) ? IMSIC_EISTATE_PENDING : IMSIC_EISTATE_ENABLED;
 
@@ -157,10 +170,6 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
 
     if (val) {
         *val = 0;
-        for (i = 0; i < xlen; i++) {
-            mask = (target_ulong)1 << i;
-            *val |= (imsic->eistate[base + i] & state) ? mask : 0;
-        }
     }
 
     for (i = 0; i < xlen; i++) {
@@ -172,10 +181,15 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
         mask = (target_ulong)1 << i;
         if (wr_mask & mask) {
             if (new_val & mask) {
-                imsic->eistate[base + i] |= state;
+                prev = qatomic_fetch_or(&imsic->eistate[base + i], state);
             } else {
-                imsic->eistate[base + i] &= ~state;
+                prev = qatomic_fetch_and(&imsic->eistate[base + i], ~state);
             }
+        } else {
+            prev = qatomic_read(&imsic->eistate[base + i]);
+        }
+        if (val && (prev & state)) {
+            *val |= mask;
         }
     }
 
@@ -302,14 +316,14 @@ static void riscv_imsic_write(void *opaque, hwaddr addr, uint64_t value,
     page = addr >> IMSIC_MMIO_PAGE_SHIFT;
     if ((addr & (IMSIC_MMIO_PAGE_SZ - 1)) == IMSIC_MMIO_PAGE_LE) {
         if (value && (value < imsic->num_irqs)) {
-            imsic->eistate[(page * imsic->num_irqs) + value] |=
-                                                    IMSIC_EISTATE_PENDING;
+            qatomic_or(&imsic->eistate[(page * imsic->num_irqs) + value],
+                       IMSIC_EISTATE_PENDING);
+
+            /* Update CPU external interrupt status */
+            riscv_imsic_update(imsic, page);
         }
     }
 
-    /* Update CPU external interrupt status */
-    riscv_imsic_update(imsic, page);
-
     return;
 
 err: