icache: Fix icbi potentially clobbering the icache (#192)
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 5 Jun 2020 06:23:23 +0000 (16:23 +1000)
committerGitHub <noreply@github.com>
Fri, 5 Jun 2020 06:23:23 +0000 (16:23 +1000)
icbi currently just resets the icache. This has some nasty side
effects such as also clearing the TLB, but also the wishbone interface.

That means that any ongoing cycle will be dropped.

However, most of our slaves don't handle that well and will continue
sending acks for already issued requests.

Under some circumstances we can thus restart an icache load and get
spurious ack/data from the wishbone left over from the "cancelled"
sequence.

This has broken booting Linux for me.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
core.vhdl
icache.vhdl
icache_tb.vhdl

index d02609b51d8f4476174e1d8d9cf2bb800c3a2582..8ba5b70eefaf50382e2b0dc66e5cfbacae770ddd 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -159,7 +159,7 @@ begin
         if rising_edge(clk) then
             rst_fetch1  <= core_rst;
             rst_fetch2  <= core_rst;
-            rst_icache  <= core_rst or dbg_icache_rst or ex1_icache_inval;
+            rst_icache  <= core_rst;
             rst_dcache  <= core_rst;
             rst_dec1    <= core_rst;
             rst_dec2    <= core_rst;
@@ -202,6 +202,7 @@ begin
             i_out => icache_to_fetch2,
             m_in => mmu_to_icache,
             flush_in => flush,
+            inval_in => dbg_icache_rst or ex1_icache_inval,
            stall_out => icache_stall_out,
             wishbone_out => wishbone_insn_out,
             wishbone_in => wishbone_insn_in
index 553b885e151b1178da58fee76976157b747b26c9..264a96316073dbe61464f48a666dae31beb01a4a 100644 (file)
@@ -54,6 +54,7 @@ entity icache is
 
        stall_out    : out std_ulogic;
        flush_in     : in std_ulogic;
+       inval_in     : in std_ulogic;
 
         wishbone_out : out wishbone_master_out;
         wishbone_in  : in wishbone_slave_out
@@ -173,6 +174,7 @@ architecture rtl of icache is
        store_way        : way_t;
         store_index      : index_t;
        store_row        : row_t;
+        store_valid      : std_ulogic;
 
         -- TLB miss state
         fetch_failed     : std_ulogic;
@@ -570,6 +572,14 @@ begin
                -- Not useful normally but helps avoiding tons of sim warnings
                r.wb.adr <= (others => '0');
             else
+                -- Process cache invalidations
+                if inval_in = '1' then
+                    for i in index_t loop
+                        cache_valids(i) <= (others => '0');
+                    end loop;
+                    r.store_valid <= '0';
+                end if;
+
                -- Main state machine
                case r.state is
                when IDLE =>
@@ -599,6 +609,7 @@ begin
                        r.store_index <= req_index;
                        r.store_way <= replace_way;
                        r.store_row <= get_row(req_laddr);
+                        r.store_valid <= '1';
 
                        -- Prep for first wishbone read. We calculate the address of
                        -- the start of the cache line and start the WB cycle.
@@ -638,7 +649,7 @@ begin
                            r.wb.cyc <= '0';
 
                            -- Cache line is now valid
-                           cache_valids(r.store_index)(r.store_way) <= '1';
+                           cache_valids(r.store_index)(r.store_way) <= r.store_valid and not inval_in;
 
                            -- We are done
                            r.state <= IDLE;
index 828a6102f6b64c6ebd0aeb191e4f055490586bad..39e28d5e9fffc7588685392535205f9121145f9a 100644 (file)
@@ -34,6 +34,7 @@ begin
             i_out => i_in,
             m_in => m_out,
            flush_in => '0',
+            inval_in => '0',
             wishbone_out => wb_bram_in,
             wishbone_in => wb_bram_out
             );