xics: Implement destination server field in interrupt source registers

This implements the server field in the XISRs (external interrupt
source registers), allowing each interrupt source to be directed to a
particular CPU.  If the CPU number that is written is out of range,
CPU 0 is used.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/436/head
Paul Mackerras 3 weeks ago
parent 3924ed0f49
commit 9bd6b3d175

@ -252,12 +252,14 @@ package common is


-- For now, fixed 16 sources, make this either a parametric -- For now, fixed 16 sources, make this either a parametric
-- package of some sort or an unconstrainted array. -- package of some sort or an unconstrainted array.
-- We don't know NCPUS or SRC_NUM here, so make this
-- large enough for 4 cpus and 16 interrupt sources for now.
type ics_to_icp_t is record type ics_to_icp_t is record
-- Level interrupts only, ICS just keeps prsenting the -- Level interrupts only, ICS just keeps prsenting the
-- highest priority interrupt. Once handling edge, something -- highest priority interrupt. Once handling edge, something
-- smarter involving handshake & reject support will be needed -- smarter involving handshake & reject support will be needed
src : std_ulogic_vector(3 downto 0); src : std_ulogic_vector(15 downto 0); -- 4 bits each for 4 cpus
pri : std_ulogic_vector(7 downto 0); pri : std_ulogic_vector(31 downto 0); -- 8 bits each for 4 cpus
end record; end record;


-- This needs to die... -- This needs to die...

@ -980,6 +980,7 @@ begin


xics_ics: entity work.xics_ics xics_ics: entity work.xics_ics
generic map( generic map(
NCPUS => NCPUS,
SRC_NUM => 16, SRC_NUM => 16,
PRIO_BITS => 3 PRIO_BITS => 3
) )

@ -181,9 +181,9 @@ begin
v.icp(i).xisr := x"000000"; v.icp(i).xisr := x"000000";
v.icp(i).irq := '0'; v.icp(i).irq := '0';


if i = 0 and ics_in.pri /= x"ff" then if ics_in.pri(8*i + 7 downto 8*i) /= x"ff" then
v.icp(i).xisr := x"00001" & ics_in.src; v.icp(i).xisr := x"00001" & ics_in.src(4*i + 3 downto 4*i);
pending_priority := ics_in.pri; pending_priority := ics_in.pri(8*i + 7 downto 8*i);
end if; end if;


-- Check MFRR -- Check MFRR
@ -235,6 +235,7 @@ use work.helpers.all;


entity xics_ics is entity xics_ics is
generic ( generic (
NCPUS : natural := 1;
SRC_NUM : integer range 1 to 256 := 16; SRC_NUM : integer range 1 to 256 := 16;
PRIO_BITS : integer range 1 to 8 := 3 PRIO_BITS : integer range 1 to 8 := 3
); );
@ -253,10 +254,13 @@ end xics_ics;
architecture rtl of xics_ics is architecture rtl of xics_ics is


constant SRC_NUM_BITS : natural := log2(SRC_NUM); constant SRC_NUM_BITS : natural := log2(SRC_NUM);
constant SERVER_NUM_BITS : natural := 2;


subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0); subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
subtype server_t is unsigned(SERVER_NUM_BITS-1 downto 0);
type xive_t is record type xive_t is record
pri : pri_t; pri : pri_t;
server : server_t;
end record; end record;
constant pri_masked : pri_t := (others => '1'); constant pri_masked : pri_t := (others => '1');


@ -333,6 +337,16 @@ architecture rtl of xics_ics is
return p(nbits - 1 downto 0); return p(nbits - 1 downto 0);
end function; end function;


function server_check(serv_in: std_ulogic_vector(7 downto 0)) return unsigned is
variable srv : server_t;
begin
srv := to_unsigned(0, SERVER_NUM_BITS);
if to_integer(unsigned(serv_in)) < NCPUS then
srv := unsigned(serv_in(SERVER_NUM_BITS - 1 downto 0));
end if;
return srv;
end;

-- Register map -- Register map
-- 0 : Config -- 0 : Config
-- 4 : Debug/diagnostics -- 4 : Debug/diagnostics
@ -391,16 +405,14 @@ begin
be_out := (others => '0'); be_out := (others => '0');


if reg_is_xive = '1' then if reg_is_xive = '1' then
be_out := int_level_l(reg_idx) & be_out(31) := int_level_l(reg_idx);
'0' & be_out(29) := int_level_l(reg_idx);
int_level_l(reg_idx) & be_out(8 + SERVER_NUM_BITS - 1 downto 8) := std_ulogic_vector(xives(reg_idx).server);
'0' & be_out(7 downto 0) := prio_unpack(xives(reg_idx).pri);
x"00000" &
prio_unpack(xives(reg_idx).pri);
elsif reg_is_config = '1' then elsif reg_is_config = '1' then
be_out := get_config; be_out := get_config;
elsif reg_is_debug = '1' then elsif reg_is_debug = '1' then
be_out := x"00000" & icp_out_next.src & icp_out_next.pri; be_out := icp_out_next.src & icp_out_next.pri(15 downto 0);
end if; end if;
wb_out.dat <= bswap(be_out); wb_out.dat <= bswap(be_out);
wb_out.ack <= wb_valid; wb_out.ack <= wb_valid;
@ -414,17 +426,20 @@ begin
if rising_edge(clk) then if rising_edge(clk) then
if rst = '1' then if rst = '1' then
for i in 0 to SRC_NUM - 1 loop for i in 0 to SRC_NUM - 1 loop
xives(i) <= (pri => pri_masked); xives(i) <= (pri => pri_masked, server => to_unsigned(0, SERVER_NUM_BITS));
end loop; end loop;
elsif wb_valid = '1' and wb_in.we = '1' then elsif wb_valid = '1' and wb_in.we = '1' then
-- Byteswapped input -- Byteswapped input
be_in := bswap(wb_in.dat); be_in := bswap(wb_in.dat);
if reg_is_xive then if reg_is_xive then
-- TODO: When adding support for other bits, make sure to if wb_in.sel(3) = '1' then
-- properly implement wb_in.sel to allow partial writes. xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
xives(reg_idx).pri <= prio_pack(be_in(7 downto 0)); report "ICS irq " & integer'image(reg_idx) &
report "ICS irq " & integer'image(reg_idx) & " set to pri:" & to_hstring(be_in(7 downto 0));
" set to:" & to_hstring(be_in(7 downto 0)); end if;
if wb_in.sel(2) = '1' then
xives(reg_idx).server <= server_check(be_in(15 downto 8));
end if;
end if; end if;
end if; end if;
end if; end if;
@ -449,29 +464,36 @@ begin
variable pending_pri : pri_vector_t; variable pending_pri : pri_vector_t;
variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0); variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
begin begin
-- Work out the most-favoured (lowest) priority of the pending interrupts icp_out_next.src <= (others => '0');
pending_pri := (others => '0'); icp_out_next.pri <= (others => '0');
for i in 0 to SRC_NUM - 1 loop for cpu in 0 to NCPUS-1 loop
if int_level_l(i) = '1' then -- Work out the most-favoured (lowest) priority of the interrupts
pending_pri := pending_pri or prio_decode(xives(i).pri); -- that are pending and directed to this cpu
end if; pending_pri := (others => '0');
end loop; for i in 0 to SRC_NUM - 1 loop
max_pri := priority_encoder(pending_pri, PRIO_BITS); if int_level_l(i) = '1' and to_integer(xives(i).server) = cpu then
pending_pri := pending_pri or prio_decode(xives(i).pri);
end if;
end loop;
max_pri := priority_encoder(pending_pri, PRIO_BITS);

-- Work out which interrupts are pending at that priority
pending_at_pri := (others => '0');
for i in 0 to SRC_NUM - 1 loop
if int_level_l(i) = '1' and xives(i).pri = max_pri and
to_integer(xives(i).server) = cpu then
pending_at_pri(i) := '1';
end if;
end loop;
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);


-- Work out which interrupts are pending at that priority if max_pri /= pri_masked then
pending_at_pri := (others => '0'); report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri)) &
for i in 0 to SRC_NUM - 1 loop " srv=" & integer'image(cpu);
if int_level_l(i) = '1' and xives(i).pri = max_pri then
pending_at_pri(i) := '1';
end if; end if;
icp_out_next.src(4*cpu + 3 downto 4*cpu) <= max_idx;
icp_out_next.pri(8*cpu + 7 downto 8*cpu) <= prio_unpack(max_pri);
end loop; end loop;
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);

if max_pri /= pri_masked then
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri));
end if;
icp_out_next.src <= max_idx;
icp_out_next.pri <= prio_unpack(max_pri);
end process; end process;


end architecture rtl; end architecture rtl;

Loading…
Cancel
Save