Implement slbia as a dTLB/iTLB flush

Slbia (with IH=7) is used in the Linux kernel to flush the ERATs
(our iTLB/dTLB), so make it do that.

This moves the logic to work out whether to flush a single entry
or the whole TLB from dcache and icache into mmu.  We now invalidate
all dTLB and iTLB entries when the AP (actual pagesize) field of
RB is non-zero on a tlbie[l], as well as when IS is non-zero.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/169/head
Paul Mackerras 5 years ago
parent f54a65f8cf
commit a658766fcf

@ -227,6 +227,7 @@ package common is
valid : std_ulogic; valid : std_ulogic;
op : insn_type_t; -- what ld/st or m[tf]spr or TLB op to do op : insn_type_t; -- what ld/st or m[tf]spr or TLB op to do
nia : std_ulogic_vector(63 downto 0); nia : std_ulogic_vector(63 downto 0);
insn : std_ulogic_vector(31 downto 0);
addr1 : std_ulogic_vector(63 downto 0); addr1 : std_ulogic_vector(63 downto 0);
addr2 : std_ulogic_vector(63 downto 0); addr2 : std_ulogic_vector(63 downto 0);
data : std_ulogic_vector(63 downto 0); -- data to write, unused for read data : std_ulogic_vector(63 downto 0); -- data to write, unused for read
@ -242,12 +243,11 @@ package common is
rc : std_ulogic; -- set for stcx. rc : std_ulogic; -- set for stcx.
virt_mode : std_ulogic; -- do translation through TLB virt_mode : std_ulogic; -- do translation through TLB
priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0) priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0)
spr_num : spr_num_t; -- SPR number for mfspr/mtspr
end record; end record;
constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0', constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
sign_extend => '0', update => '0', xerc => xerc_init, sign_extend => '0', update => '0', xerc => xerc_init,
reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0', reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0',
spr_num => 0, others => (others => '0')); others => (others => '0'));


type Loadstore1ToExecute1Type is record type Loadstore1ToExecute1Type is record
exception : std_ulogic; exception : std_ulogic;
@ -283,6 +283,7 @@ package common is
type Loadstore1ToMmuType is record type Loadstore1ToMmuType is record
valid : std_ulogic; valid : std_ulogic;
tlbie : std_ulogic; tlbie : std_ulogic;
slbia : std_ulogic;
mtspr : std_ulogic; mtspr : std_ulogic;
iside : std_ulogic; iside : std_ulogic;
load : std_ulogic; load : std_ulogic;
@ -305,6 +306,7 @@ package common is
type MmuToDcacheType is record type MmuToDcacheType is record
valid : std_ulogic; valid : std_ulogic;
tlbie : std_ulogic; tlbie : std_ulogic;
doall : std_ulogic;
tlbld : std_ulogic; tlbld : std_ulogic;
addr : std_ulogic_vector(63 downto 0); addr : std_ulogic_vector(63 downto 0);
pte : std_ulogic_vector(63 downto 0); pte : std_ulogic_vector(63 downto 0);
@ -320,6 +322,7 @@ package common is
type MmuToIcacheType is record type MmuToIcacheType is record
tlbld : std_ulogic; tlbld : std_ulogic;
tlbie : std_ulogic; tlbie : std_ulogic;
doall : std_ulogic;
addr : std_ulogic_vector(63 downto 0); addr : std_ulogic_vector(63 downto 0);
pte : std_ulogic_vector(63 downto 0); pte : std_ulogic_vector(63 downto 0);
end record; end record;

@ -210,6 +210,7 @@ architecture rtl of dcache is
type reg_stage_0_t is record type reg_stage_0_t is record
req : Loadstore1ToDcacheType; req : Loadstore1ToDcacheType;
tlbie : std_ulogic; tlbie : std_ulogic;
doall : std_ulogic;
tlbld : std_ulogic; tlbld : std_ulogic;
mmu_req : std_ulogic; -- indicates source of request mmu_req : std_ulogic; -- indicates source of request
end record; end record;
@ -456,11 +457,13 @@ begin
r0.req.data <= m_in.pte; r0.req.data <= m_in.pte;
r0.req.byte_sel <= (others => '1'); r0.req.byte_sel <= (others => '1');
r0.tlbie <= m_in.tlbie; r0.tlbie <= m_in.tlbie;
r0.doall <= m_in.doall;
r0.tlbld <= m_in.tlbld; r0.tlbld <= m_in.tlbld;
r0.mmu_req <= '1'; r0.mmu_req <= '1';
else else
r0.req <= d_in; r0.req <= d_in;
r0.tlbie <= '0'; r0.tlbie <= '0';
r0.doall <= '0';
r0.tlbld <= '0'; r0.tlbld <= '0';
r0.mmu_req <= '0'; r0.mmu_req <= '0';
end if; end if;
@ -572,7 +575,6 @@ begin


tlb_update : process(clk) tlb_update : process(clk)
variable tlbie : std_ulogic; variable tlbie : std_ulogic;
variable tlbia : std_ulogic;
variable tlbwe : std_ulogic; variable tlbwe : std_ulogic;
variable repl_way : tlb_way_t; variable repl_way : tlb_way_t;
variable eatag : tlb_tag_t; variable eatag : tlb_tag_t;
@ -580,17 +582,9 @@ begin
variable pteset : tlb_way_ptes_t; variable pteset : tlb_way_ptes_t;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
tlbie := '0'; tlbie := r0_valid and r0.tlbie;
tlbia := '0';
tlbwe := r0_valid and r0.tlbld; tlbwe := r0_valid and r0.tlbld;
if r0_valid = '1' and r0.tlbie = '1' then if rst = '1' or (tlbie = '1' and r0.doall = '1') then
if r0.req.addr(11 downto 10) /= "00" then
tlbia := '1';
else
tlbie := '1';
end if;
end if;
if rst = '1' or tlbia = '1' then
-- clear all valid bits at once -- clear all valid bits at once
for i in tlb_index_t loop for i in tlb_index_t loop
dtlb_valids(i) <= (others => '0'); dtlb_valids(i) <= (others => '0');

@ -282,6 +282,7 @@ architecture behaviour of decode1 is
2#0010111010# => (ALU, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- prtyd 2#0010111010# => (ALU, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- prtyd
2#0010011010# => (ALU, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- prtyw 2#0010011010# => (ALU, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- prtyw
-- 2#0010000000# setb -- 2#0010000000# setb
2#0111110010# => (LDST, OP_TLBIE, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- slbia
2#0000011011# => (ALU, OP_SHL, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- sld 2#0000011011# => (ALU, OP_SHL, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- sld
2#0000011000# => (ALU, OP_SHL, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- slw 2#0000011000# => (ALU, OP_SHL, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- slw
2#1100011010# => (ALU, OP_SHR, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '1', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0'), -- srad 2#1100011010# => (ALU, OP_SHR, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '1', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0'), -- srad

@ -1023,7 +1023,7 @@ begin
lv.xerc := v.e.xerc; lv.xerc := v.e.xerc;
lv.reserve := e_in.reserve; lv.reserve := e_in.reserve;
lv.rc := e_in.rc; lv.rc := e_in.rc;
lv.spr_num := decode_spr_num(e_in.insn); lv.insn := e_in.insn;
-- decode l*cix and st*cix instructions here -- decode l*cix and st*cix instructions here
if e_in.insn(31 downto 26) = "011111" and e_in.insn(10 downto 9) = "11" and if e_in.insn(31 downto 26) = "011111" and e_in.insn(10 downto 9) = "11" and
e_in.insn(5 downto 1) = "10101" then e_in.insn(5 downto 1) = "10101" then

@ -435,32 +435,19 @@ begin


-- iTLB update -- iTLB update
itlb_update: process(clk) itlb_update: process(clk)
variable tlbie : std_ulogic;
variable tlbia : std_ulogic;
variable tlbwe : std_ulogic;
variable wr_index : tlb_index_t; variable wr_index : tlb_index_t;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
tlbie := '0';
tlbia := '0';
tlbwe := m_in.tlbld;
if m_in.tlbie = '1' then
if m_in.addr(11 downto 10) /= "00" then
tlbia := '1';
else
tlbie := '1';
end if;
end if;
wr_index := hash_ea(m_in.addr); wr_index := hash_ea(m_in.addr);
if rst = '1' or tlbia = '1' then if rst = '1' or (m_in.tlbie = '1' and m_in.doall = '1') then
-- clear all valid bits -- clear all valid bits
for i in tlb_index_t loop for i in tlb_index_t loop
itlb_valids(i) <= '0'; itlb_valids(i) <= '0';
end loop; end loop;
elsif tlbie = '1' then elsif m_in.tlbie = '1' then
-- clear entry regardless of hit or miss -- clear entry regardless of hit or miss
itlb_valids(wr_index) <= '0'; itlb_valids(wr_index) <= '0';
elsif tlbwe = '1' then elsif m_in.tlbld = '1' then
itlb_tags(wr_index) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS); itlb_tags(wr_index) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS);
itlb_ptes(wr_index) <= m_in.pte; itlb_ptes(wr_index) <= m_in.pte;
itlb_valids(wr_index) <= '1'; itlb_valids(wr_index) <= '1';

@ -166,7 +166,7 @@ begin
mfspr := '0'; mfspr := '0';
mmu_mtspr := '0'; mmu_mtspr := '0';
itlb_fault := '0'; itlb_fault := '0';
sprn := std_ulogic_vector(to_unsigned(l_in.spr_num, 10)); sprn := std_ulogic_vector(to_unsigned(decode_spr_num(l_in.insn), 10));
sprval := (others => '0'); -- avoid inferred latches sprval := (others => '0'); -- avoid inferred latches
exception := '0'; exception := '0';
dsisr := (others => '0'); dsisr := (others => '0');
@ -468,6 +468,7 @@ begin
m_out.mtspr <= mmu_mtspr; m_out.mtspr <= mmu_mtspr;
m_out.sprn <= sprn(3 downto 0); m_out.sprn <= sprn(3 downto 0);
m_out.addr <= addr; m_out.addr <= addr;
m_out.slbia <= l_in.insn(7);
m_out.rs <= l_in.data; m_out.rs <= l_in.data;


-- Update outputs to writeback -- Update outputs to writeback

@ -168,6 +168,7 @@ begin
variable tlb_load : std_ulogic; variable tlb_load : std_ulogic;
variable itlb_load : std_ulogic; variable itlb_load : std_ulogic;
variable tlbie_req : std_ulogic; variable tlbie_req : std_ulogic;
variable inval_all : std_ulogic;
variable rts : unsigned(5 downto 0); variable rts : unsigned(5 downto 0);
variable mbits : unsigned(5 downto 0); variable mbits : unsigned(5 downto 0);
variable pgtable_addr : std_ulogic_vector(63 downto 0); variable pgtable_addr : std_ulogic_vector(63 downto 0);
@ -191,6 +192,7 @@ begin
tlb_load := '0'; tlb_load := '0';
itlb_load := '0'; itlb_load := '0';
tlbie_req := '0'; tlbie_req := '0';
inval_all := '0';


-- Radix tree data structures in memory are big-endian, -- Radix tree data structures in memory are big-endian,
-- so we need to byte-swap them -- so we need to byte-swap them
@ -217,6 +219,10 @@ begin
if l_in.tlbie = '1' then if l_in.tlbie = '1' then
dcreq := '1'; dcreq := '1';
tlbie_req := '1'; tlbie_req := '1';
-- Invalidate all iTLB/dTLB entries for tlbie with
-- RB[IS] != 0 or RB[AP] != 0, or for slbia
inval_all := l_in.slbia or l_in.addr(11) or l_in.addr(10) or
l_in.addr(7) or l_in.addr(6) or l_in.addr(5);
v.state := TLB_WAIT; v.state := TLB_WAIT;
else else
v.valid := '1'; v.valid := '1';
@ -356,12 +362,14 @@ begin


d_out.valid <= dcreq; d_out.valid <= dcreq;
d_out.tlbie <= tlbie_req; d_out.tlbie <= tlbie_req;
d_out.doall <= inval_all;
d_out.tlbld <= tlb_load; d_out.tlbld <= tlb_load;
d_out.addr <= addr; d_out.addr <= addr;
d_out.pte <= tlb_data; d_out.pte <= tlb_data;


i_out.tlbld <= itlb_load; i_out.tlbld <= itlb_load;
i_out.tlbie <= tlbie_req; i_out.tlbie <= tlbie_req;
i_out.doall <= inval_all;
i_out.addr <= addr; i_out.addr <= addr;
i_out.pte <= tlb_data; i_out.pte <= tlb_data;



Loading…
Cancel
Save