From bb54af59de6c71261e4893ba7a59305c415b63ce Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 22 Jun 2020 23:38:34 +1000 Subject: [PATCH] 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 --- soc.vhdl | 3 +- tests/test_xics.bin | Bin 12392 -> 12392 bytes tests/xics/xics.c | 24 ++++++++------ xics.vhdl | 75 ++++++++++++++++++++++++++++++++------------ 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/soc.vhdl b/soc.vhdl index c096ac1..c3b47bc 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -640,7 +640,8 @@ begin xics_ics: entity work.xics_ics generic map( - SRC_NUM => 16 + SRC_NUM => 16, + PRIO_BITS => 3 ) port map( clk => system_clk, diff --git a/tests/test_xics.bin b/tests/test_xics.bin index 1e0e7d4efb6797d25fb75383564b2575119dd3e2..8ad9b3a58ee372b9966f84e7b065a6e9f1a539af 100755 GIT binary patch delta 715 zcmaEn@FHPC2&2lz&}?4D8JiFCS}^l+G1#tQVW`mxXQ*Xhoy;bvCj#b%In;t_KZRNb zh6Ibr1ws;=0|Z+b8C54=6)I=EFxgi)MS@MimLb9`QGvm$5@H5W@c{>0mdPiD)fqJ= ze-swiybRQQ@ZW!LD8iWZSUd)C#p30j+g|K&(FzK5>k@|#A|?d z_lk>aiZdoysQ!l7?aP9&ivg&w5s7aw`K-7xP!FSoxTZ8v&&FR6JvW(A_3)zTag;D; zJTbXaLYgsl@>B_Vp#H5A`hqurZj40IXE6Dzgg2)~ZngD|oG5F9$)1w)8FePVlr(32 zI9XB3nNeVJs+6;&1kgoO86mbYGW@rm@c+LzC zU<)Io>Ex$E<%|y|#|oziH7M9JM0h1CFnCo$^e9Zu7nhv;Mp%SVVltzMxaN7F)`S24 zds_kNm+TB43_!E~|4*{Hkdtg7%Yoo4Om-9zW^|Z*QABuhh6qS^t%$hY6`(FxsP0@e z-3yWU3c1M^6QO(tCZHV$9BdE#pL|I~O;Q3V6$+ICIf50+zByS?R9q0`3{_-V{ zE24R+mVrUR(tttH0u&Am4E8@SOr9v35AvXxxaK>c*ug(g53(XW^Z?{RHUuB&K{02r zYfeH{fm~AwWq+MKS4>Ls zGbUK5{)X7?%Yv}$1JImCB)-DryW++`J%SSAn&Ln`8-GFc++;@8!;7LPP{N$?#^g>3 zX~x{iOC{ui`j1NJ3!VU)9f_n*VKS?vH>X5ywe^XdC~Jkuk&^QnZ6^PeG-v!c*-*-v zkzsPFl(QrU&?i$FA+|9x{I{O)|GzgV83;_iC?(Dqv-zdeWJbmZn`>p7g(o%$OfnE) a^q4GYV6G4&42(=5m>>$FS;QeUj06CZDb4@@ diff --git a/tests/xics/xics.c b/tests/xics/xics.c index 8a0c13b..a867744 100644 --- a/tests/xics/xics.c +++ b/tests/xics/xics.c @@ -168,8 +168,8 @@ int xics_test_0(void) assert(v0 = 0xff); assert(v1 = 0xff); - ics_write_xive(0xaa, 0); - ics_write_xive(0x55, 1); + ics_write_xive(0xa, 0); + ics_write_xive(0x5, 1); v0 = ics_read_xive(0); v1 = ics_read_xive(1); #ifdef DEBUG @@ -181,11 +181,15 @@ int xics_test_0(void) print_number(v1); puts("\n"); #endif - assert(v0 = 0xaa); - assert(v1 = 0x55); + assert(v0 = 0xa); + assert(v1 = 0x5); ics_write_xive(0xff, 0); ics_write_xive(0xff, 1); + v0 = ics_read_xive(0); + v1 = ics_read_xive(1); + assert(v0 = 0xff); + assert(v1 = 0xff); return 0; } @@ -198,28 +202,28 @@ int xics_test_1(void) icp_write8(XICS_XIRR, 0x00); // mask all interrupts // trigger two interrupts - potato_uart_irq_en(); // cause 0x500 interrupt - ics_write_xive(0x80, 0); - icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt + potato_uart_irq_en(); // cause serial interrupt + ics_write_xive(0x6, 0); // set source to prio 6 + icp_write8(XICS_MFRR, 0x04); // cause ipi interrupt at prio 5 // still masked, so shouldn't happen yet delay(); assert(isrs_run == 0); // unmask IPI only - icp_write8(XICS_XIRR, 0x40); + icp_write8(XICS_XIRR, 0x6); delay(); assert(isrs_run == ISR_IPI); // unmask UART - icp_write8(XICS_XIRR, 0xc0); + icp_write8(XICS_XIRR, 0x7); delay(); assert(isrs_run == (ISR_IPI | ISR_UART)); // cleanup icp_write8(XICS_XIRR, 0x00); // mask all interrupts potato_uart_irq_dis(); - ics_write_xive(0, 0); + ics_write_xive(0, 0xff); isrs_run = 0; return 0; diff --git a/xics.vhdl b/xics.vhdl index 9f97fec..b644051 100644 --- a/xics.vhdl +++ b/xics.vhdl @@ -211,7 +211,8 @@ use work.wishbone_types.all; entity xics_ics is generic ( - SRC_NUM : positive := 16 + SRC_NUM : integer range 1 to 256 := 16; + PRIO_BITS : integer range 1 to 8 := 8 ); port ( clk : in std_logic; @@ -227,10 +228,12 @@ end xics_ics; 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 pri : pri_t; end record; + constant pri_masked : pri_t := (others => '1'); + type xive_array_t is array(0 to SRC_NUM-1) of xive_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 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); begin r( 7 downto 0) := v(31 downto 24); @@ -249,8 +252,35 @@ architecture rtl of xics_ics is return r; end function; - -- Register map - -- 0 : Config (currently hard wired base irq#) + function get_config return std_ulogic_vector is + 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 -- 800 : XIVE0 -- 804 : XIVE1 ... @@ -258,6 +288,7 @@ architecture rtl of xics_ics is -- Config register format: -- -- 23.. 0 : Interrupt base (hard wired to 16) + -- 27.. 24 : #prio bits (1..8) -- -- XIVE register format: -- @@ -311,9 +342,9 @@ begin int_level_l(reg_idx) & '0' & x"00000" & - xives(reg_idx).pri; + prio_unpack(xives(reg_idx).pri); 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 be_out := x"00000" & icp_out_next.src & icp_out_next.pri; end if; @@ -332,21 +363,22 @@ begin if rising_edge(clk) then if rst = '1' then for i in 0 to SRC_NUM - 1 loop - xives(i) <= (pri => x"ff"); + xives(i) <= (pri => pri_masked); end loop; elsif wb_valid = '1' and wb_in.we = '1' then if reg_is_xive then -- TODO: When adding support for other bits, make sure to -- properly implement wb_in.sel to allow partial writes. - xives(reg_idx).pri <= be_in(7 downto 0); - report "ICS irq " & integer'image(reg_idx) & " set to:" & to_hstring(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)); end if; end if; end if; end 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 -- system between ICSs' (plural) and ICP incl. reject etc... @@ -364,16 +396,19 @@ begin -- A more favored than b ? function a_mf_b(a: pri_t; b: pri_t) return boolean is - variable a_i : integer range 0 to 255; - variable b_i : integer range 0 to 255; + variable a_i : unsigned(PRIO_BITS-1 downto 0); + variable b_i : unsigned(PRIO_BITS-1 downto 0); begin - a_i := to_integer(unsigned(a)); - b_i := to_integer(unsigned(b)); - return a < b; + a_i := unsigned(a); + b_i := unsigned(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; begin -- XXX FIXME: Use a tree - max_pri := x"ff"; + max_pri := pri_masked; max_idx := 0; 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 @@ -381,11 +416,11 @@ begin max_idx := i; end if; end loop; - if max_pri /= x"ff" then - report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(max_pri); + if max_pri /= pri_masked then + report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(prio_unpack(max_pri)); end if; 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 architecture rtl;