xics: Add support for reduced priority field size

This makes the ICS support less than the 8 architected bits
and sets the soc to use 3 bits by default.

All the supported bits set translates to "masked" (and will read
back at 0xff), any small value is used as-is.

Linux doesn't use priorities above 5, so this is a way to save
silicon. The number of supported priority bits is exposed to the
OS via the config register.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
pull/210/head
Benjamin Herrenschmidt 4 years ago
parent 5c2fc47e2c
commit bb54af59de

@ -640,7 +640,8 @@ begin


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

Binary file not shown.

@ -168,8 +168,8 @@ int xics_test_0(void)
assert(v0 = 0xff); assert(v0 = 0xff);
assert(v1 = 0xff); assert(v1 = 0xff);


ics_write_xive(0xaa, 0); ics_write_xive(0xa, 0);
ics_write_xive(0x55, 1); ics_write_xive(0x5, 1);
v0 = ics_read_xive(0); v0 = ics_read_xive(0);
v1 = ics_read_xive(1); v1 = ics_read_xive(1);
#ifdef DEBUG #ifdef DEBUG
@ -181,11 +181,15 @@ int xics_test_0(void)
print_number(v1); print_number(v1);
puts("\n"); puts("\n");
#endif #endif
assert(v0 = 0xaa); assert(v0 = 0xa);
assert(v1 = 0x55); assert(v1 = 0x5);


ics_write_xive(0xff, 0); ics_write_xive(0xff, 0);
ics_write_xive(0xff, 1); ics_write_xive(0xff, 1);
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
assert(v0 = 0xff);
assert(v1 = 0xff);
return 0; return 0;
} }


@ -198,28 +202,28 @@ int xics_test_1(void)
icp_write8(XICS_XIRR, 0x00); // mask all interrupts icp_write8(XICS_XIRR, 0x00); // mask all interrupts


// trigger two interrupts // trigger two interrupts
potato_uart_irq_en(); // cause 0x500 interrupt potato_uart_irq_en(); // cause serial interrupt
ics_write_xive(0x80, 0); ics_write_xive(0x6, 0); // set source to prio 6
icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt icp_write8(XICS_MFRR, 0x04); // cause ipi interrupt at prio 5


// still masked, so shouldn't happen yet // still masked, so shouldn't happen yet
delay(); delay();
assert(isrs_run == 0); assert(isrs_run == 0);


// unmask IPI only // unmask IPI only
icp_write8(XICS_XIRR, 0x40); icp_write8(XICS_XIRR, 0x6);
delay(); delay();
assert(isrs_run == ISR_IPI); assert(isrs_run == ISR_IPI);


// unmask UART // unmask UART
icp_write8(XICS_XIRR, 0xc0); icp_write8(XICS_XIRR, 0x7);
delay(); delay();
assert(isrs_run == (ISR_IPI | ISR_UART)); assert(isrs_run == (ISR_IPI | ISR_UART));


// cleanup // cleanup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts icp_write8(XICS_XIRR, 0x00); // mask all interrupts
potato_uart_irq_dis(); potato_uart_irq_dis();
ics_write_xive(0, 0); ics_write_xive(0, 0xff);
isrs_run = 0; isrs_run = 0;


return 0; return 0;

@ -211,7 +211,8 @@ use work.wishbone_types.all;


entity xics_ics is entity xics_ics is
generic ( generic (
SRC_NUM : positive := 16 SRC_NUM : integer range 1 to 256 := 16;
PRIO_BITS : integer range 1 to 8 := 8
); );
port ( port (
clk : in std_logic; clk : in std_logic;
@ -227,10 +228,12 @@ end xics_ics;


architecture rtl of xics_ics is architecture rtl of xics_ics is


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

type xive_array_t is array(0 to SRC_NUM-1) of xive_t; type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
signal xives : xive_array_t; signal xives : xive_array_t;


@ -239,7 +242,7 @@ architecture rtl of xics_ics is
signal icp_out_next : ics_to_icp_t; signal icp_out_next : ics_to_icp_t;
signal int_level_l : std_ulogic_vector(SRC_NUM - 1 downto 0); signal int_level_l : std_ulogic_vector(SRC_NUM - 1 downto 0);


function bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is function bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
variable r : std_ulogic_vector(31 downto 0); variable r : std_ulogic_vector(31 downto 0);
begin begin
r( 7 downto 0) := v(31 downto 24); r( 7 downto 0) := v(31 downto 24);
@ -249,8 +252,35 @@ architecture rtl of xics_ics is
return r; return r;
end function; end function;


-- Register map function get_config return std_ulogic_vector is
-- 0 : Config (currently hard wired base irq#) variable r: std_ulogic_vector(31 downto 0);
begin
r := (others => '0');
r(23 downto 0) := std_ulogic_vector(to_unsigned(SRC_NUM, 24));
r(27 downto 24) := std_ulogic_vector(to_unsigned(PRIO_BITS, 4));
return r;
end function;

function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is
begin
return pri8(PRIO_BITS-1 downto 0);
end function;

function prio_unpack(pri: pri_t) return std_ulogic_vector is
variable r : std_ulogic_vector(7 downto 0);
begin
if pri = pri_masked then
r := x"ff";
else
r := (others => '0');
r(PRIO_BITS-1 downto 0) := pri;
end if;
return r;
end function;


-- Register map
-- 0 : Config
-- 4 : Debug/diagnostics -- 4 : Debug/diagnostics
-- 800 : XIVE0 -- 800 : XIVE0
-- 804 : XIVE1 ... -- 804 : XIVE1 ...
@ -258,6 +288,7 @@ architecture rtl of xics_ics is
-- Config register format: -- Config register format:
-- --
-- 23.. 0 : Interrupt base (hard wired to 16) -- 23.. 0 : Interrupt base (hard wired to 16)
-- 27.. 24 : #prio bits (1..8)
-- --
-- XIVE register format: -- XIVE register format:
-- --
@ -311,9 +342,9 @@ begin
int_level_l(reg_idx) & int_level_l(reg_idx) &
'0' & '0' &
x"00000" & x"00000" &
xives(reg_idx).pri; prio_unpack(xives(reg_idx).pri);
elsif reg_is_config = '1' then elsif reg_is_config = '1' then
be_out := std_ulogic_vector(to_unsigned(SRC_NUM, 32)); 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 := x"00000" & icp_out_next.src & icp_out_next.pri;
end if; end if;
@ -332,21 +363,22 @@ 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 => x"ff"); xives(i) <= (pri => pri_masked);
end loop; end loop;
elsif wb_valid = '1' and wb_in.we = '1' then elsif wb_valid = '1' and wb_in.we = '1' then
if reg_is_xive then if reg_is_xive then
-- TODO: When adding support for other bits, make sure to -- TODO: When adding support for other bits, make sure to
-- properly implement wb_in.sel to allow partial writes. -- properly implement wb_in.sel to allow partial writes.
xives(reg_idx).pri <= be_in(7 downto 0); xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
report "ICS irq " & integer'image(reg_idx) & " set to:" & to_hstring(be_in(7 downto 0)); report "ICS irq " & integer'image(reg_idx) &
" set to:" & to_hstring(be_in(7 downto 0));
end if; end if;
end if; end if;
end if; end if;
end process; end process;


-- generate interrupt. This is a simple combinational process, -- generate interrupt. This is a simple combinational process,
-- potentially wasteul in HW for large number of interrupts. -- potentially wasteful in HW for large number of interrupts.
-- --
-- could be replaced with iterative state machines and a message -- could be replaced with iterative state machines and a message
-- system between ICSs' (plural) and ICP incl. reject etc... -- system between ICSs' (plural) and ICP incl. reject etc...
@ -364,16 +396,19 @@ begin


-- A more favored than b ? -- A more favored than b ?
function a_mf_b(a: pri_t; b: pri_t) return boolean is function a_mf_b(a: pri_t; b: pri_t) return boolean is
variable a_i : integer range 0 to 255; variable a_i : unsigned(PRIO_BITS-1 downto 0);
variable b_i : integer range 0 to 255; variable b_i : unsigned(PRIO_BITS-1 downto 0);
begin begin
a_i := to_integer(unsigned(a)); a_i := unsigned(a);
b_i := to_integer(unsigned(b)); b_i := unsigned(b);
return a < b; report "a_mf_b a=" & to_hstring(a) &
" b=" & to_hstring(b) &
" r=" & boolean'image(a < b);
return a_i < b_i;
end function; end function;
begin begin
-- XXX FIXME: Use a tree -- XXX FIXME: Use a tree
max_pri := x"ff"; max_pri := pri_masked;
max_idx := 0; max_idx := 0;
for i in 0 to SRC_NUM - 1 loop for i in 0 to SRC_NUM - 1 loop
if int_level_l(i) = '1' and a_mf_b(xives(i).pri, max_pri) then if int_level_l(i) = '1' and a_mf_b(xives(i).pri, max_pri) then
@ -381,11 +416,11 @@ begin
max_idx := i; max_idx := i;
end if; end if;
end loop; end loop;
if max_pri /= x"ff" then if max_pri /= pri_masked then
report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(max_pri); report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(prio_unpack(max_pri));
end if; end if;
icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4)); icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4));
icp_out_next.pri <= max_pri; icp_out_next.pri <= prio_unpack(max_pri);
end process; end process;


end architecture rtl; end architecture rtl;

Loading…
Cancel
Save