From c2dcf4b3348e4b1eb9ef6a2284b411e12c007033 Mon Sep 17 00:00:00 2001
From: Paul Mackerras <paulus@ozlabs.org>
Date: Thu, 2 Jan 2025 13:22:49 +1100
Subject: [PATCH] dcache: Generate a DSI on larx/stcx to non-cacheable memory

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
---
 common.vhdl     | 1 +
 dcache.vhdl     | 8 +++++---
 loadstore1.vhdl | 4 +++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/common.vhdl b/common.vhdl
index b1a2c8e..425bb79 100644
--- a/common.vhdl
+++ b/common.vhdl
@@ -626,6 +626,7 @@ package common is
         store_done : std_ulogic;
         error : std_ulogic;
         cache_paradox : std_ulogic;
+        reserve_nc : std_ulogic;
     end record;
 
     type DcacheEventType is record
diff --git a/dcache.vhdl b/dcache.vhdl
index 1a1087c..5eb659d 100644
--- a/dcache.vhdl
+++ b/dcache.vhdl
@@ -353,6 +353,7 @@ architecture rtl of dcache is
         mmu_done         : std_ulogic;
         mmu_error        : std_ulogic;
         cache_paradox    : std_ulogic;
+        reserve_nc       : std_ulogic;
 
         -- Signal to complete a failed stcx.
         stcx_fail        : std_ulogic;
@@ -1125,7 +1126,7 @@ begin
                 else
                     req_op_flush <= '1';
                 end if;
-            elsif nc = '1' and is_hit = '1' then
+            elsif nc = '1' and (is_hit = '1' or r0.req.reserve = '1') then
                 req_op_bad <= '1';
             elsif r0.req.load = '0' then
                 req_op_store <= '1';   -- includes dcbz
@@ -1167,6 +1168,7 @@ begin
         d_out.store_done <= not r1.stcx_fail;
         d_out.error <= r1.ls_error;
         d_out.cache_paradox <= r1.cache_paradox;
+        d_out.reserve_nc <= r1.reserve_nc;
 
         -- Outputs to MMU
         m_out.done <= r1.mmu_done;
@@ -1354,16 +1356,16 @@ begin
             r1.hit_load_valid <= req_op_load_hit;
             r1.cache_hit <= req_op_load_hit or (req_op_store and req_is_hit);     -- causes PLRU update
 
+            r1.cache_paradox <= access_ok and req_nc and req_is_hit;
+            r1.reserve_nc <= access_ok and r0.req.reserve and req_nc;
             if req_op_bad = '1' then
                 report "Signalling ld/st error valid_ra=" & std_ulogic'image(valid_ra) &
                     " rc_ok=" & std_ulogic'image(rc_ok) & " perm_ok=" & std_ulogic'image(perm_ok);
                 r1.ls_error <= not r0.mmu_req;
                 r1.mmu_error <= r0.mmu_req;
-                r1.cache_paradox <= access_ok;
             else
                 r1.ls_error <= '0';
                 r1.mmu_error <= '0';
-                r1.cache_paradox <= '0';
             end if;
 
             -- Record TLB hit information for updating TLB PLRU
diff --git a/loadstore1.vhdl b/loadstore1.vhdl
index 69d053d..5e69352 100644
--- a/loadstore1.vhdl
+++ b/loadstore1.vhdl
@@ -738,7 +738,8 @@ begin
         end if;
 
         interrupt := (r2.req.valid and r2.req.align_intr) or
-                     (d_in.error and d_in.cache_paradox) or m_in.err;
+                     (d_in.error and (d_in.cache_paradox or d_in.reserve_nc)) or
+                     m_in.err;
         if interrupt = '1' then
             v.req.valid := '0';
             v.busy := '0';
@@ -905,6 +906,7 @@ begin
                 -- signal an interrupt straight away
                 exception := '1';
                 dsisr(63 - 38) := not r2.req.load;
+                dsisr(63 - 37) := d_in.reserve_nc;
                 -- XXX there is no architected bit for this
                 -- (probably should be a machine check in fact)
                 dsisr(63 - 35) := d_in.cache_paradox;